日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue 全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。
Promise静态方法
这篇文章只记录实现,不记录用法。
之前我们封装了一个符合 promise/A+ 规范的类库 Promise,那现在我们来实现一下类库中包含的静态方法。
Promise.resolve()
Promise.resolve(100)
等价于 new Promise((resolve,reject)=>{resolve(100)})
实现此方法非常简单,在我们实现好的类库中添加静态方法。
1 2 3 4 5
| static resolve(val) { return new Promise((resolve, reject) => { resolve(val) }) }
|
Promise.reject()
Promise.reject(100)
等价于 new Promise((resolve,reject)=>{reject(100)})
实现此方法也非常简单,在我们实现好的类库中添加静态方法。
1 2 3 4 5
| static reject(val) { return new Promise((resolve, reject) => { reject(val) }) }
|
Promise.catch()
Promise.catch()
等价于 .then(null, () => {})
所以我们可以直接在类库中实现此方法
1 2 3
| catch (errorFn) { return this.then(null, errorFn) }
|
Promise.all()
现有如下代码
1 2 3 4 5 6 7 8 9
| let promise1 = new Promise((resolve, reject) => {resolve(100)}) let promise2 = new Promise((resolve, reject) => {reject(200)}) let promise3 = new Promise((resolve, reject) => {resolve(300)}) let promise4 = new Promise((resolve, reject) => {resolve(400)}) Promise.all([promise1, promise2, promise3, promise4]).then(result => { console.log(result); }).catch(reason => { console.log(reason); })
|
有多个Promise实例,当所有的实例都执行完毕后,才会执行其成功结果。当其中有一个实例失败了,整个Promise.all的结果都会变成失败。
根据上述结论,我们可以试着实现Promise.all()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| static all(promises) { return new Promise((resolve, reject) => { let results = [] let times = 0 const processSuccess = (index, val) => { results[index] = val; if (++times === promises.length) { resolve(results) } } for (let i = 0; i < promises.length; i++) { let p = promises[i]; if (p && typeof p.then === 'function') { p.then(result => { processSuccess(i, result) }, reject) } else { processSuccess(i, p) } } }) }
|
Promise.race()
有多个Promise实例,最先执行完成的实例返回结果后,整个Promise.race 就执行完毕了。
1 2 3 4 5 6 7 8 9 10 11 12
| static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { let p = promises[i] if (p && typeof p.then === 'function') { p.then(resolve, reject) } else { resolve(p) } } }) }
|
实际案例
实际工作中,Promise.race()
可以用来处理 图片加载失败 或者 脚本加载超时 等问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function wrap(p1) { let abort; let p = new Promise((resolve, reject) => { abort = reject; }) let p2 = Promise.race([p, p1]); p2.abort = abort; return p2; }
let p1 = new Promise( ... ) let promise = wrap(p1); promise.then(result=>{ ... },reason=>{ ... })
setTimeout(() => { promise.abort(); }, 60000);
|
封装一个wrap()
函数,接受参数是 Promise 数组。在函数内设定一个属性值 abort,abort 获取值一个新的Promise中的reject方法。
这样wrap函数中的abort就相当于一个中断按钮。
Promise.finally()
无论Promise成功还是失败,都会执行此方法,他不会接受上一层 .then
方法传递的参数。
执行过后,代码会继续执行(后续的 .then
方法会继续执行),如果在.finally()
中返回一个新的 Promise,Promise除了失败结果,任何结果都不会被传递下去。
1 2 3 4 5 6 7 8 9
| finally(onFinally) { return this.then( value => Promise.resolve(onFinally()).then(() => value), reason => Promise.resolve(onFinally()).then(() => { throw reason }) ) }
|
Promise.allSettled
有多个Promise实例,当所有的实例都执行完毕后,会将所有结果全部返回,无论结果是正确还是错误的。所以他不会走.catch
方法。
Promise.any
有多个Promise实例,如果其中有一个成功了,就会走其成功结果(取出第一个成功的值),只有全部失败了,才会走失败结果。
promisify
我在上一篇文章中,曾经封装过一个 Promise 的异步函数 readFile ,当时用了一种很麻烦的封装方式。
1 2 3 4 5 6 7 8 9 10
| const fs = require('fs'); function readFile(path, encoding) { return new Promise((resolve, reject) => { fs.readFile(path, encoding, (err, data) => { if (err) reject(err) resolve(data) }) }) } readFile('./a.txt', 'utf8').then(result => { console.log(result) })
|
那我们有没有什么简单的方法可以使用呢?答案是 有的。
Node中内置模块 util
中有一个 promisify
方法,可以神奇的将 异步函数 转换成 Promise。
1 2 3 4
| const fs = require('fs'); const util = require('util'); let readFile = util.promisify(fs.readFile) readFile('./a.txt', 'utf8').then(result => { console.log(result) })
|
现在我们可以尝试自己手写一下其 实现原理
1 2 3 4 5 6 7 8 9 10
| function promisify(readFile) { return function (...args) { return new Promise((resolve, reject) => { readFile(...args, (err, data) => { if (err) return reject(err) resolve(data) }) }) } }
|
这样我们就手写了一个 promisify
方法。
本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的 个人站点、博客园 和 掘金,我会在文章产出后同步上传到这些平台上。
最后感谢您的支持!