Promise.prototype.finally
finally()
方法返回一个 Promise
。在 promise
结束时,无论结果是 fulfilled
或者是 rejected
,都会执行指定的回调函数
那怎么实现呢? 直接往 then
方法塞两个回调不就完事!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
Promise.prototype.finally = function (fn) { return this.then(function (value) { return Promise.resolve(fn()).then(function () { return value }) }, function (reason){ return Promise.reject(fn()).then(function () { return reason }) }) }
|
1 2 3 4 5 6 7 8
| Promise.prototype.finally = function (fn) { return this.then(value => { return Promise.resolve(fn()).then(() => value) }, reason => { return Promise.reject(fn()).then(() => reason) }) }
|
这方法有啥用呢?比如你在处理异步请求的时候,经常会使用 loading
,是不是事后无论请求成功或者失败都要把 loading
去掉,一般就是用在无论失败或成功都需要执行的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var load = false new Promise(function (resolve, reject) { load = true setTimeout(function () { console.log('in pending: ' + load) if(Math.random() > 0.5){ resolve() }else{ reject() } }, 100) }).then(function(){ console.log('in fulfilled: ' + load) }).catch(function(){ console.log('in rejected: ' + load) }).finally(function () { load = false console.log('in finally: ' + load) })
|
Promise.prototype.catch
这个其实没啥好讲的,其实等于 this.then(null, fn)
1 2 3 4 5 6 7 8
|
Promise.prototype.catch = function (fn) { return this.then(null, fn) }
|
使用方法极其简单
1 2 3
| Promise.reject().catch(function(){ console.log('in catch') })
|
Promise.reject & Promise.resolve
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
|
Promise.reject = function (reason) { return new Promise(function(resolve, reject){ var fn = function () { reject(reason) } if(reason instanceof Promise){ reason.then(fn, fn) }else { fn() } }) }
Promise.reject = function (reason) { return new Promise((resolve, reject) => { const fn = () => reject(reason) reason instanceof Promise ? reason.then(fn, fn) : fn() }) } Promise.reject(new Promise(res => { console.log('in promise') res(2) })).then(v => console.log('in then ' + v)) .catch(v => console.log('in catch ', v))
|
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
|
Promise.resolve = function (value) { if(value instanceof Promise) return value return new Promise(function(resolve, reject){ resolve(value) }) }
Promise.resolve = function (value) { return value instanceof Promise ? value : new Promise(resolve => resolve(value)) } Promise.resolve(new Promise((res, rej) => { console.log('in promise') res(2) })).then(v => console.log('in then ' + v)) .catch(v => console.log('in catch ', v))
Promise.resolve(new Promise((res, rej) => { console.log('in promise') rej(2) })).then(v => console.log('in then ' + v)) .catch(v => console.log('in catch ', v))
|
接下来就是面试经常问到的四个方法了
Promise.all
Promise.all
是所有 Promise
结果都为 fulfilled
时才会执行 then
方法的回调!
值得注意的是,all
方法接收的是一个迭代器对象,很多实现代码上来就是一个 for
循环的写法是不对的!
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
|
Promise.all = function (iterable) { return new Promise(function(resolve, reject){ var iteratee = iterable[Symbol.iterator]() var len = 0 var i = 0 var res = null var result = [] while (true){ res = iteratee.next() if(res.done) break !(function(j){ len++ var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value val.then(function(value){ result[j] = value i++ if(len === i && res.done) resolve(result) }, function(reason){ reject(reason) }) })(len) } }) };
Promise.all = function (iterable) { return new Promise((resolve, reject) => { const promiseList = [...iterable] const result = [] let j = 0 let len = promiseList.length promiseList.forEach((val, i) => { val = !(val instanceof Promise) ? Promise.resolve(val) : val val.then(value => { result[i] = value j++ if(len <= j) resolve(result) }, reason => reject(reason)) }) }) };
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [ new Map([[Promise.resolve(1), Promise.resolve(2)]]), new Set([Promise.resolve(1), Promise.resolve(2)]), [Promise.resolve(1), Promise.resolve(2)], new Set([Promise.reject(1), Promise.resolve(2)]), [Promise.reject(1), Promise.resolve(2)], [1, '1', true, false, null, undefined, {}, function(){}, Symbol(), Promise.resolve(2)] ].forEach(item => { Promise.all(item).then(v => { console.log(v) }).catch(r => { console.log('in catch ' + r) }) })
|
Promise.any
Promise.any
是只要有一个 Promise
结果都为 fulfilled
时就会执行 then
方法的回调!
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
|
Promise.any = function (iterable) { return new Promise(function(resolve, reject){ var iteratee = iterable[Symbol.iterator]() var res = null var len = 0 var i = 0 while (true){ res = iteratee.next() if(res.done) break len++ var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value val.then(function(value){ i++ resolve(value) }, function(reason){ i++ if(i >= len && res.done){ reject(reason) } }) } }) };
Promise.any = function (iterable) { return new Promise((resolve, reject) => { const promiseList = [...iterable] const len = promiseList.length let i = 0 promiseList.forEach(val => { val = !(val instanceof Promise) ? Promise.resolve(val) : val val.then(value => { i++ resolve(value) }, reason => { i++ if(i >= len){ reject(reason) } }) }) }) };
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [ new Map([[Promise.resolve(1), Promise.resolve(2)]]), new Set([Promise.resolve(1), Promise.resolve(2)]), [Promise.resolve(1), Promise.resolve(2)], new Set([Promise.reject(1), Promise.resolve(2)]), [Promise.reject(1), Promise.resolve(2)], [1, '1', true, false, null, undefined, {}, function(){}, Symbol(), Promise.resolve(2)] ].forEach(item => { Promise.any(item).then(v => { console.log(v) }).catch(r => { console.log('in catch ' + r) }) })
|
Promise.race
Promise.race
是只要有一个 Promise
产生结果时就会执行 then
方法的回调!
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
|
Promise.race = function (iterable) { return new Promise(function(resolve, reject){ var iteratee = iterable[Symbol.iterator]() var res = null var done = false while (true){ res = iteratee.next() if(res.done) break var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value val.then(function(value){ if(done) return done = true resolve(value) }, function(reason){ if(done) return done = true reject(reason) }) } }) }; Promise.race = function (iterable) { return new Promise(function(resolve, reject){ const promiseList = [...iterable] let done = false promiseList.forEach(val => { val = !(val instanceof Promise) ? Promise.resolve(val) : val val.then(value => { if(done) return done = true resolve(value) }, reason => { if(done) return done = true reject(reason) }) }) }) };
|
Promise.allSettled
Promise.allSettled
返回一个在所有给定的promise都已经fulfilled或rejected后的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
|
Promise.allSettled = function (iterable) { return new Promise(function(resolve){ var iteratee = iterable[Symbol.iterator]() var res = null var i = 0 var len = 0 var result = [] var allSettled = function(){ i++ if(len <= i && res.done) resolve(result) } while (true){ res = iteratee.next() if(res.done) break !(function(j){ var val = !(res.value instanceof Promise) ? Promise.resolve(res.value) : res.value val.then(function(value){ result[j] = { value: value, status: 'fulfilled' } allSettled() }, function(reason){ result[j] = { reason: reason, status: 'rejected' } allSettled() }) }(len)) len += 1 } }) }; Promise.allSettled = function (iterable) { return new Promise(resolve => { const promiseList = [...iterable] const result = [] const len = promiseList.length let j = 0 var allSettled = () => len <= ++j && resolve(result) promiseList.forEach((val, i) => { var val = !(val instanceof Promise) ? Promise.resolve(val) : val val.then(value => { result[i] = { value: value, status: 'fulfilled' } allSettled() }, reason => { result[i] = { reason: reason, status: 'rejected' } allSettled() }) }) }) };
|
搞定收工!
源码地址