状态初始化
promise用法
let p = new Promise((res, rej) => { // res('success') rej('err') }) console.log(p1); // [[PromiseState]]: "fulfilled" // [[PromiseResult]]: "success"
promise初始化实现
首先,确定promise用一个类可以实现,promise初始化时,需要知道promise的状态,以及promise的返回值。
在promise中,存在PromiseState、PromiseResult两属性,分别存放promise的状态和结果。
用户在new Promise时,传入的是一个回调函数,在函数中使用resolve、rejected。
- 在调用resolve时,将状态修改为fulfilled,并给结果赋值。
- 在调用reject时,将状态修改为rejected,并给结果赋值。
初始化如下:
class MyPromise { constructor(cb) { this['[[PromiseState]]'] = 'pending' this['[[PromiseResult]]'] = undefined this.onResolved = [] // 成功回调集合 两个集合暂未使用 this.onRejected = [] // 存放失败的回调集合 cb(this.#resolve.bind(this), this.#reject.bind(this)) // 需要绑定this,否则获取不到 } #resolve(val) { this['[[PromiseState]]'] = 'fulfilled' this['[[PromiseResult]]'] = val } #reject(val) { this['[[PromiseState]]'] = 'rejected' this['[[PromiseResult]]'] = val } }
如果在cb调用不对promise内部私有属性绑定this,运行后就会报错:
this输出为undefined,此时获取不到this,所以需要在cb调用时,绑定this。
静态方法
resolve
Promise.resolve() 返回一个解析过的promise对象。
使用方法
console.log(Promise.resolve('success')); // Promise{ // [[PromiseState]]: "fulfilled" // [[PromiseResult]]: "success" // }
实现
直接使用resolve静态方法,输出的结果等同于 new Promise((res, rej) => { res('success') })
。因此,在调用resolve方法时,需要实例化一个Promise类,在内部调用res。
static resolve(val) { return new MyPromise((res, rej) => { res(val) }) }
reject
Promise.reject() 返回一个拒绝的Promise对象。
使用方法
console.log(Promise.reject('err')); // Promise{ // [[PromiseState]]: "rejected" // [[PromiseResult]]: "err" // }
实现
直接使用resolve静态方法,输出的结果等同于 new Promise((res, rej) => { rej('err') })
。
static reject(val) { return new MyPromise((res, rej) => { rej(val) }) }
allSettled
Promise.allSettled() 接收一个由已经执行完promise(状态为:fulfilled或rejected)的结果组成的对象数组。
allSettled用法
let p2 = new Promise((res, rej) => { setTimeout(() => { res("p1"); }, 2000); }) let p3 = new Promise((res, rej) => { setTimeout(() => { rej("p2 err"); }, 1000); }) Promise.allSettled([p2, p3]).then(res => { console.log(res); // [{status: "fulfilled", value: "p1"},{status: "rejected", reason: "p2 err"}] })
实现方法
allSettled接收的是一个对象数组,不管状态如何,结果输出的也是一个数组。在数组循环调用then时,需要考虑两种状态的返回结果,在不同的状态中,分别设置该项中的数据返回格式。例如:{status: "fulfilled", value: "p1"},成功中两个属性分别为status和value。
在实现时,需要设置一个变量,存储返回新结果的长度num。如果num等于接收数组lists长度,则表明已经全部修改统一格式,此时就需要执行下一步回调。
static allSettled(lists) { let resArr = new Array(lists.length) let num = 0 return new MyPromise((resolve) => { lists.forEach((item, key) => { let obj = {} item.then( (res) => { obj['status'] = 'fulfilled' obj['value'] = res resArr[key] = obj num++ if (num >= lists.length) { resolve(resArr) } }, (err) => { obj['status'] = 'rejected' obj['reason'] = err resArr[key] = obj num++ if (num >= lists.length) { resolve(resArr) } }, ) }) }) }
all
Promise.all 等待所有的都完成,如果all中数组有一个错误,则执行异常。
all用法
let p2 = new Promise((res, rej) => { setTimeout(() => { res("p1"); }, 2000); }) let p3 = new Promise((res, rej) => { setTimeout(() => { res("p2"); }, 1000); }) Promise.all([p2, p3]) .then(res => { console.log(res); }) // ["p1", "p2"]
all实现
和allSettled类似,只需要考虑成功的情况,但是还是需要判断所有的是否都已执行完成。
static all(lists) { let newArr = new Array(lists.length) let num = 0 return new MyPromise((resolve) => { lists.forEach((item, key) => { item.then((res) => { newArr[key] = res num++ if (num >= lists.length) { resolve(newArr) } }) }) }) }
race
Promise.race()谁执行的时间短就执行谁,无论状态如何。
race用法
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('failed') }, 500) }) Promise.race([p1, p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 打开的是 'failed' })
race实现
在遍历lists时,直接调用then。
static race(lists) { return new MyPromise((resolve, reject) => { lists.forEach((item) => { item.then( (res) => { resolve(res) }, (err) => { reject(err) }, ) }) }) }
any
Promise.any()返回成功状态中的第一个。
any用法
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('failed') }, 500) }) Promise.any([p1, p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) }) // success
any实现
执行成功状态的第一个回调。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例。
static any(lists) { return new MyPromise((resolve, reject) => { let errs = [] let len = lists.length if (len === 0) reject(new AggregateError('All promises were rejected')) lists.forEach(item => { item.then(res => { resolve(res) }, err => { len-- errs.push(err) if (len === 0) reject(new AggregateError(errs)) }) }) }) }
原型方法
then原型方法
Promise.prototype.then() 最多接收两个回调函数:成功和失败情况下的回调函数。
基本then
基本then用法
let p = new Promise((res, rej) => { res('success'); }) p.then(res => { console.log(res); // success }, err => { console.log(err); })
基本then的实现
通过上段then的基本用法,可以根据new Promise内执行的res或rej,then中分别对应正确的回调或抛出错误。在then中就可以判断promise的状态来执行不同的回调。
then(onFullfill, onReject) { if (this['[[PromiseState]]'] === 'fulfilled') { onFullfill(this['[[PromiseResult]]']) } if (this['[[PromiseState]]'] === 'rejected') { onReject(this['[[PromiseResult]]']) } }
状态为fulfilled时,表示成功;为rejected,表示失败。 调用多个then时,根据promise中调用的释放回调用,同时多个then中相应的回调也会触发。
let p = new MyPromise((res, rej) => { res('success') }); p.then(res => { console.log(res); }, err => { console.log('err', err); }) p.then((res) => { console.log(res, '2'); }, (rej) => { console.log('err2'); }) // success // success 2
then的链式调用
then的链式用法
let p1 = new Promise((res, rej) => { res('success'); }) p1.then(res => { return new Promise((res, rej) => { res('success2') }) }, err => { console.log(err); }).then(res => { console.log('2', res); // 2 success2 })
then的链式实现
链式的实现,就相当于返回一个promise。根据上一个promise的状态,在then中执行相应状态的回调,依次类推。如果上一个then中返回一个promise,则此时then中的状态为'pending'。
#resolve(val) { if (this['[[PromiseState]]'] !== 'pending') return setTimeout(() => { this['[[PromiseState]]'] = 'fulfilled' this['[[PromiseResult]]'] = val // this.onResolvedQueue.forEach((fn) => fn && fn(val)) let cb; while(cb = this.onResolvedQueue.shift()) { cb(val) } }) } #reject(err) { if (this['[[PromiseState]]'] !== 'pending') return setTimeout(() => { this['[[PromiseState]]'] = 'rejected' this['[[PromiseResult]]'] = err // this.onRejectedQueue.forEach((fn) => fn && fn(err)) let cb; while(cb = this.onRejectedQueue.shift()) { cb(err) } }) } then(onFullfill, onReject) { // 返回的是新promise return new MyPromise((resolve, reject) => { // 成功执行的函数 let onFullfillFn = (val) => { let res = onFullfill && onFullfill(val) // 返回一个新的promise 执行下一个回调 res instanceof MyPromise ? res.then(resolve) : resolve(res) } // 失败执行的函数 let rejectFn = (err) => { onReject && onReject(err) reject(err) } this.onResolvedQueue.push(onFullfillFn) this.onRejectedQueue.push(rejectFn) }) }
then中会接受最多两个的回调函数,在成功的回调中,传入的可能直接是逻辑处理,也可能是需要返回一个新的promise对象,所以在返回时,需要判断返回类型。如果传入的是失败函数,直接执行用户失败的回调。
catch原型方法
Promise.prototype.catch() 捕获rejected情况,并处理。
catch用法
let p = new Promise((res, rej) => { rej('err') }) p.catch((reason) => { console.log(reason) // err })
catch实现
直接执行then的失败回调。
catch(cb) { this.then(undefined, cb) }
finally原型方法
Promise.prototype.finally() 无论是fulfiled还是rejected,都会执行finally内的回调函数。
finally用法
let p = new Promise((res, rej) => { res('success') }) p.then((reason) => { console.log(reason) }).finally(() => { console.log('finally'); }) // success finally
finally实现
finally(cb) { return this.then(cb, cb) }