此篇博文转载自瓶子君的blog 链接 ,并加以自己的理解和注释。
Promise本质 Promise就是为了解决callback的问题而产生的。
Promise 本质上就是一个绑定了回调的对象,而不是将回调传回函数内部。
开门见山,Promise解决的是回调函数处理异步的第2个问题:控制反转 。
我们把上面那个多层回调嵌套的例子用Promise的方式重构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 let getPromise1 = function ( ) { return new Promsie(function (resolve, reject ) { $.ajax({ url : 'XXX1' , success : function (data ) { let key = data; resolve(key); }, error : function (err ) { reject(err); } }); }); }; let getPromise2 = function (key ) { return new Promsie(function (resolve, reject ) { $.ajax({ url : 'XXX2' , data : { key : key }, success : function (data ) { resolve(data); }, error : function (err ) { reject(err); } }); }); }; let getPromise3 = function ( ) { return new Promsie(function (resolve, reject ) { $.ajax({ url : 'XXX3' , success : function (data ) { resolve(data); }, error : function (err ) { reject(err); } }); }); }; getPromise1() .then(function (key ) { return getPromise2(key); }) .then(function (data ) { return getPromise3(data); }) .then(function (data ) { console .log('业务数据:' , data); }) .catch(function (err ) { console .log(err); });
Promise 在一定程度上其实改善了回调函数的书写方式;另外逻辑性更明显了,将异步业务提取成单个函数,整个流程可以看到是一步步向下执行的,依赖层级也很清晰,最后需要的数据是在整个代码的最后一步获得。
所以,Promise在一定程度上解决了回调函数的书写结构问题,但回调函数依然在主流程上存在,只不过都放到了then(…)里面,和我们大脑顺序线性的思维逻辑还是有出入的。
Promise 是什么 Promise是什么,无论是ES6的Promise也好,jQuery的Promise也好,不同的库有不同的实现,但是大家遵循的都是同一套规范,所以,Promise并不指特定的某个实现,它是一种规范,是一套处理JavaScript异步的机制 。
Promise的规范会多,如Promise/A、Promise/B、Promise/D以及Promise/A的升级版Promise/A+,其中ES6遵循Promise/A+规范,有关Promise/A+,你可以参考一下:
这里只简要介绍下几点与接下来内容相关的规范:
Promise 本质是一个状态机,每个 Promise 有三种状态:pending、resolved以及rejected。状态转变只能是pending —resolved 或者 pending —rejected。状态转变不可逆。
then 方法可以被同一个 promise 调用多次。
then 方法必须返回一个 promise。规范2.2.7中规定, then 必须返回一个新的 Promise
值穿透
Promise 实现及源码解读 首先,我们看一下Promise的简单使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var p = new Promise (function (resolve, reject ) { if () { resolve('Success!' ); } else { reject('Failure!' ); } }); p.then(function ( ) { }).catch(function ( ) { })
我们通过这种使用构建Promise实现的第一个版本
自己的写法也是结合调用实例的逆推过程 。
为什么要将callback单独传入呢?因为啊,new Promise(… ) 这括号里的函数逻辑是由我们编写的,可调整可修改,在任何条件下的resolve和reject,所以封装的时候最好写成一个通用的回调函数。
Promise构建版本一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function MyPromise (callback ) { var _this = this _this.value = void 0 var onResolvedCallback var onRejectedCallback _this.resolve = function (value ) { onResolvedCallback() } _this.reject = function (error ) { onRejectedCallback() } callback(_this.resolve, _this.reject) } MyPromise.prototype.then = function (resolve, reject ) {}
大致框架已经出来了,但我们看到Promise状态、reslove函数、reject函数以及then等都没有处理。
Promise构建之二:链式存储 链式存储:讲的就是promise实例会有很多次then,然后下一次的then都会获得上一次的then的结果,就像链式一般。将结果存储下去,直至return。
首先,举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 new Promise (function (resolve, reject ) { setTimeout (function ( ) { var a=1 ; resolve(a); }, 1000 ); }).then(function (res ) { console .log(res); return new Promise (function (resolve, reject ) { setTimeout (function ( ) { var b=2 ; resolve(b); }, 1000 ); }) }).then(function (res ) { console .log(res); return new Promise (function (resolve, reject ) { setTimeout (function ( ) { var c=3 resolve(c); }, 1000 ); }) }).then(function (res ) { console .log(res); })
上例结果是每间隔1s打印一个数字,顺序为1、2、3。
这里保证了:
让a,b,c的值能在then里面的回调接收到
在连续调用异步,如何确保异步函数的执行顺序
Promise一个常见的需求就是连续执行两个或者多个异步操作,这种情况下,每一个后来的操作都在前面的操作执行成功之后,带着上一步操作所返回的结果开始执行。这里用setTimeout
来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function MyPromise (callback ) { var _this = this _this.value = void 0 _this.onResolvedCallbacks = [] _this.onRejectedCallbacks = [] _this.resolve = function (value ) { setTimeout (() => { _this.onResolvedCallbacks.forEach(cb =cb()) }) } _this.reject = function (error ) { setTimeout (() => { _this.onRejectedCallbacks.forEach(cb =cb()) }) } callback(_this.resolve, _this.reject) } MyPromise.prototype.then = function ( ) {}
Promise构建之三:状态机制、顺序执行 为了保证Promise的异步操作时的顺序执行,这里给Promise加上状态机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 const PENDING = "pending" const RESOLVED = "resolved" const REJECTED = "rejected" function MyPromise (callback ) { var _this = this _this.currentState = PENDING _this.value = void 0 _this.onResolvedCallbacks = [] _this.onRejectedCallbacks = [] _this.resolve = function (value ) { setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = RESOLVED _this.value = value _this.onResolvedCallbacks.forEach(cb => cb()) } }) } _this.reject = function (value ) { setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = REJECTED _this.value = value _this.onRejectedCallbacks.forEach(cb => cb()) } }) } callback(_this.resolve, _this.reject) } MyPromise.prototype.then = function ( ) {}
Promise构建之四:递归执行 每个Promise后面链接一个对象,该对象包含onresolved,onrejected,子promise三个属性.
当父Promise 状态改变完毕,执行完相应的onresolved/onrejected的时候,拿到子promise,在等待这个子promise状态改变,在执行相应的onresolved/onrejected。依次循环直到当前promise没有子promise。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const PENDING = "pending" const RESOLVED = "resolved" const REJECTED = "rejected" function MyPromise (callback ) { var _this = this _this.currentState = PENDING _this.value = void 0 _this.onResolvedCallbacks = [] _this.onRejectedCallbacks = [] _this.resolve = function (value ) { if (value instanceof MyPromise) { return value.then(_this.resolve, _this.reject) } setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = RESOLVED _this.value = value _this.onResolvedCallbacks.forEach(cb => cb()) } }) } _this.reject = function (value ) { setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = REJECTED _this.value = value _this.onRejectedCallbacks.forEach(cb => cb()) } }) } callback(_this.resolve, _this.reject) } MyPromise.prototype.then = function ( ) {}
Promise构建之五:异常处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 const PENDING = "pending" const RESOLVED = "resolved" const REJECTED = "rejected" function MyPromise (callback ) { var _this = this _this.currentState = PENDING _this.value = void 0 _this.onResolvedCallbacks = [] _this.onRejectedCallbacks = [] _this.resolve = function (value ) { if (value instanceof MyPromise) { return value.then(_this.resolve, _this.reject) } setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = RESOLVED _this.value = value _this.onResolvedCallbacks.forEach(cb => cb()) } }) } _this.reject = function (error ) { setTimeout (() => { if (_this.currentState === PENDING) { _this.currentState = REJECTED _this.value = value _this.onRejectedCallbacks.forEach(cb => cb()) } }) } try { callback(_this.resolve, _this.reject) } catch (e) { _this.reject(e) } } MyPromise.prototype.then = function ( ) {}
Promise构建之六:then的实现 then 方法是 Promise 的核心,这里做一下详细介绍。
1 promise.then(onFulfilled, onRejected)
一个 Promise 的then接受两个参数: onFulfilled和onRejected(都是可选参数,并且为函数,若不是函数将被忽略)
onFulfilled 特性:
当 Promise 执行结束后其必须被调用,其第一个参数为 promise 的终值,也就是 resolve 传过来的值
在 Promise 执行结束前不可被调用
其调用次数不可超过一次
onRejected 特性
当 Promise 被拒绝执行后其必须被调用,第一个参数为 Promise 的拒绝原因,也就是reject传过来的值
在 Promise 执行结束前不可被调用
其调用次数不可超过一次
调用时机onFulfilled
和 onRejected
只有在执行环境 堆栈仅包含平台代码 时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)
调用要求onFulfilled
和 onRejected
必须被作为函数调用(即没有 this
值,在 严格模式(strict) 中,函数 this
的值为 undefined
;在非严格模式中其为全局对象。)
多次调用then
方法可以被同一个 promise
调用多次
当 promise
成功执行时,所有 onFulfilled
需按照其注册顺序依次回调
当 promise
被拒绝执行时,所有的 onRejected
需按照其注册顺序依次回调
返回then
方法会返回一个Promise
,关于这一点,Promise/A+标准并没有要求返回的这个Promise是一个新的对象,但在Promise/A标准中,明确规定了then要返回一个新的对象,目前的Promise实现中then几乎都是返回一个新的Promise(详情 )对象,所以在我们的实现中,也让then返回一个新的Promise对象。1 promise2 = promise1.then(onFulfilled, onRejected);
如果 onFulfilled
或者 onRejected
返回一个值 x
,则运行下面的 Promise 解决过程 :[[Resolve]](promise2, x)
如果 onFulfilled
或者 onRejected
抛出一个异常 e
,则 promise2
必须拒绝执行,并返回拒因 e
如果 onFulfilled
不是函数且 promise1
成功执行, promise2
必须成功执行并返回相同的值
如果 onRejected
不是函数且 promise1
拒绝执行, promise2
必须拒绝执行并返回相同的拒因
不论 promise1 被 reject 还是被 resolve , promise2 都会被 resolve,只有出现异常时才会被 rejected 。 每个Promise对象都可以在其上多次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,所以then不能返回this,因为then每次返回的Promise的结果都有可能不同。
下面代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 MyPromise.prototype.then = function (onFulfilled, onRejected ) { var _this = this var promise2 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value =value onRejected = typeof onRejected === 'function' ? onRejected : error ={throw error} if (_this.currentState === RESOLVED) { return promise2 = new MyPromise(function (resolve, reject ) { }) } if (_this.currentState === REJECTED) { return promise2 = new MyPromise(function (resolve, reject ) { }) } if (_this.currentState === PENDING) { return promise2 = new MyPromise(function (resolve, reject ) { }) } }
附:值穿透解读
1 2 3 4 5 6 MyPromise.prototype.then = function (onFulfilled, onRejected ) { ... onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value =value onRejected = typeof onRejected === 'function' ? onRejected : error ={throw error} ... }
上面提到值穿透,值穿透即:
1 2 3 4 5 6 var promise = new MyPromise((resolve, reject) ={ setTimeout (() ={ resolve('1' ) }, 1000 ) }) promise.then('2' ).then(console .log)
最终打结果是1
而不是2
再例如:
1 2 3 4 5 6 7 new MyPromise(resolve =resolve('1' )) .then() .then() .then(function foo (value ) { alert(value) })
通过 return this
只实现了值穿透的一种情况,其实值穿透有两种情况:
promise 已经是 RESOLVED/REJECTED 时,通过 return this 实现的值穿透:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var promise = new Promise (function (resolve ) { setTimeout (() ={ resolve('1' ) }, 1000 ) }) promise.then(() ={ promise.then().then((res) ={ console .log(res) }) promise.catch().then((res) ={ console .log(res) }) console .log(promise.then() === promise.catch()) console .log(promise.then(1 ) === promise.catch({name : 'anran' })) })
状况A与B处 promise 已经是 RESOLVED 了符合条件,所以执行了 return this
。 注意:原生的Promise实现里并不是这样实现的,会打印出两个false
promise 是 PENDING时,通过生成新的 promise 加入到父 promise 的 queue,父 promise 有值时调用 callFulfilled->doResolve 或 callRejected->doReject(因为 then/catch 传入的参数不是函数)设置子 promise 的状态和值为父 promise 的状态与值。如:1 2 3 4 5 6 7 8 9 10 11 12 13 14 var promise = new Promise ((resolve) ={ setTimeout (() ={ resolve('1' ) }, 1000 ) }) var a = promise.then()a.then((res) ={ console .log(res) }) var b = promise.catch()b.then((res) ={ console .log(res) }) console .log(a === b)
Promise 有三种状态,我们分3个if块来处理,每块都返回一个new Promise。
根据标准,我们知道,对于一下代码,promise2的值取决于then里面的返回值:
1 2 3 4 5 promise2 = promise1.then(function (value ) { return 1 }, function (err ) { throw new Error ('error' ) })
如果promise1被resolve了,promise2的被1
resolve,如果promise1 被reject了,promise2将被new Error('error')
reject。
所以,我们需要在then里面执行onFulfilled或者onRejected,并根据返回着(标记中记为x
)来确定promise2的结果,并且,如果onFulfilled/onRejected返回的是一个Promise,promise将直接取这个Promise的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 MyPromise.prototype.then = function (onFulfilled, onRejected ) { var _this = this var promise2 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value =value onRejected = typeof onRejected === 'function' ? onRejected : error ={throw error} if (_this.currentState === RESOLVED) { return promise2 = new MyPromise(function (resolve, reject ) { setTimeout (function ( ) { try { var x = onFulfilled(_this.value) if (x instanceof MyPromise) { x.then(resolve, reject) } resolve(x) } catch (err) { reject(err) } }) }) } if (_this.currentState === REJECTED) { return promise2 = new MyPromise(function (resolve, reject ) { setTimeout (function ( ) { try { var x = onRejected(_this.value) if (x instanceof Promise ){ x.then(resolve, reject) } } catch (err) { reject(err) } }) }) } if (_this.currentState === PENDING) { return promise2 = new MyPromise(function (resolve, reject ) { _this.onResolvedCallbacks.push(function ( ) { try { var x = onFulfilled(_this.value) if (x instanceof MyPromise) { x.then(resolve, reject) } resolve(x) } catch (err) { reject(err) } }) _this.onRejectedCallbacks.push(function ( ) { try { var x = onRejected(_this.value) if (x instanceof MyPromise) { x.then(resolve, reject) } } catch (err) { reject(err) } }) }) } }
Promise构建之七:catch的实现 1 2 3 4 MyPromise.prototype.catch = function (onRejected ) { return this .then(null , onRejected) }
至此,我们大致实现了Promise标准中所涉及到的内容。
Promise构建之八:问题补充:无缝调用 不同的Promise实现之间需要无缝的可交互,如ES6的Promise,和我们自己实现的Promise之间以及其他的Promise实现,必须是无缝调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 new MyPromise(function (resolve, reject ) { setTimeout (function ( ) { resolve('1' ) }, 1000 ) }).then(function ( ) { return new Promise .reject('2' ) }).then(function ( ) { return Q.all([ new MyPromise(resolve =resolve('3' )) new Promise .eresolve('4' ) Q.resolve('5' ) ]) })
我之前实现的代码只是判断OnFullfilled/onRejected的返回值是否为我们自己实现的实例,并没有对其他类型Promise的判断,所以,上面的代码无法正常运行。
接下来,我们解决这个问题
关于不同Promise之间的交互,其实Promise/A+标准 中有介绍,其中详细的指定了如何通过then的实参返回的值来决定promise2的状态,我们只需要按照标准把标准的内容转成代码即可。
即我们要把onFulfilled/onRejected的返回值x。当成是一个可能是Promise的对象 ,也即标准中的thenable,并以最保险的姿势调用x上的then方法,如果大家都按照标准来实现,那么不同的Promise之间就可以交互了。
而标准为了保险起见,即使x返回了一个带有then属性但不遵循Promise标准的对象(不如说这个x把它then里的两个参数都调用了,同步或者异步调用(PS,原则上then的两个参数需要异步调用,下文会讲到),或者是出错后又调用了它们,或者then根本不是一个函数),也能尽可能正确处理。
关于为何需要不同的Promise实现能够相互交互,我想原因应该是显然的,Promise并不是JS一早就有的标准,不同第三方的实现之间是并不相互知晓的,如果你使用的某一个库中封装了一个Promise实现,想象一下如果它不能跟你自己使用的Promise实现交互的场景。。。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 function resolutionProcedure (promise2, x, resolve, reject ) { if (promise2 === x) { return reject(new TypeError ("Chaining cycle detected for promise!" )) } if (x instanceof MyPromise) { if (x.currentState === PENDING) { x.then(function (value ) { resolutionProcedure(promise2, value, resolve, reject) }, reject) } else { x.then(resolve, reject) } return } let called = false if (x !== null && (typeof x === "object" || typeof x === "function" )) { try { let then = x.then if (typeof then === "function" ) { then.call( x, y ={ if (called) return called = true return resolutionProcedure(promise2, y, resolve, reject) }, r ={ if (called) return called = true return reject(r) } ) } else { resolve(x) } } catch (e) { if (called) return called = true return reject(e) } } else { resolve(x) } }
然后,我们使用resolutionProcedure
函数替换MyPromise.prototype.then
里面几处判断x是否为MyPromise对象的位置即可。即:
1 2 3 4 if (x instanceof MyPromise) { x.then(resolve, reject) }
替换为:
1 resolutionProcedure(promise2, x, resolve, reject)
总共四处,不要遗漏了
Promise构建九:完整代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 const PENDING = "pending" const RESOLVED = "resolved" const REJECTED = "rejected" function MyPromise (callback ) { var _this = this _this.currentState = PENDING _this.value = void 0 _this.onResolvedCallbacks = [] _this.onRejectedCallbacks = [] _this.resolve = function (value ) { if (value instanceof MyPromise) { return value.then(_this.resolve, _this.reject) } setTimeout (() ={ if (_this.currentState === PENDING) { _this.currentState = RESOLVED _this.value = value _this.onResolvedCallbacks.forEach(cb =cb()) } }) } _this.reject = function (value ) { setTimeout (() ={ if (_this.currentState === PENDING) { _this.currentState = REJECTED _this.value = value _this.onRejectedCallbacks.forEach(cb =cb()) } }) } try { callback(_this.resolve, _this.reject) } catch (e) { _this.reject(e) } } MyPromise.prototype.then = function (onFulfilled, onRejected ) { var _this = this var promise2 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value =value onRejected = typeof onRejected === 'function' ? onRejected : error ={throw error} if (_this.currentState === RESOLVED) { return promise2 = new MyPromise(function (resolve, reject ) { try { var x = onFulfilled(_this.value) resolutionProcedure(promise2, x, resolve, reject) } catch (err) { reject(err) } }) } if (_this.currentState === REJECTED) { return promise2 = new MyPromise(function (resolve, reject ) { try { var x = onRejected(_this.value) resolutionProcedure(promise2, x, resolve, reject) } catch (err) { reject(err) } }) } if (_this.currentState === PENDING) { return promise2 = new MyPromise(function (resolve, reject ) { _this.onResolvedCallbacks.push(function ( ) { try { var x = onFulfilled(_this.value) resolutionProcedure(promise2, x, resolve, reject) } catch (err) { reject(err) } }) _this.onRejectedCallbacks.push(function ( ) { try { var x = onRejected(_this.value) resolutionProcedure(promise2, x, resolve, reject) } catch (err) { reject(err) } }) }) } function resolutionProcedure (promise2, x, resolve, reject ) { if (promise2 === x) { return reject(new TypeError ("Chaining cycle detected for promise!" )) } if (x instanceof MyPromise) { if (x.currentState === PENDING) { x.then(function (value ) { resolutionProcedure(promise2, value, resolve, reject) }, reject) } else { x.then(resolve, reject) } return } let called = false if (x !== null && (typeof x === "object" || typeof x === "function" )) { try { let then = x.then if (typeof then === "function" ) { then.call( x, y ={ if (called) return called = true return resolutionProcedure(promise2, y, resolve, reject) }, r ={ if (called) return called = true return reject(r) } ) } else { resolve(x) } } catch (e) { if (called) return called = true return reject(e) } } else { resolve(x) } } } MyPromise.prototype.catch = function (onRejected ) { return this .then(null , onRejected) } MyPromise.prototype.finally = function (callback ) { return this .then(function (value ) { return MyPromise.resolve(callback()).then(function ( ) { return value }) }, function (err ) { return MyPromise.resolve(callback()).then(function ( ) { throw err }) }) }
额外,附加 Promise.race
与 Promise.all
的实现,有兴趣的可以了解一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 MyPromise.race = function (values ) { return new MyPromise(function (resolve, reject ) { values.forEach(function (value ) { MyPromise.resolve(value).then(resolve, reject) }) }) } MyPromise.all = function (arr ) { var args = Array .prototype.slice.call(arr) return new MyPromise(function (resolve, reject ) { if (args.length === 0 ) return resolve([]) var remaining = args.length for (var i = 0 ; i < args.length; i++) { res(i, args[i]) } function res (i, val ) { if (val && (typeof val === 'object' || typeof val === 'function' )) { if (val instanceof MyPromise && val.then === MyPromise.prototype.then) { if (val.currentState === RESOLVED) return res(i, val.value) if (val.currentState === REJECTED) reject(val.value) val.then(function (val ) { res(i, val) }, reject) return } else { var then = val.then if (typeof then === 'function' ) { var p = new MyPromise(then.bind(val)) p.then(function (val ) { res(i, val) }, reject) return } } } args[i] = val if (--remaining === 0 ) { resolve(args) } } }) }
Void 0 其实可以理解成undefined,因为undefined可以在局部函数里被覆盖,void 0 不会。
void是一个运算符,给表达式求值,返回undefined。void 0 是表达式中最短的,最节省字节。
setTimeout 如果不传时间,默认取0。
“参考”
promise取消的一些讨论