JS深挖(手撕Promise详细代码完整攻略)

目录: 1、new Promise() 2、.then()及链式调用 3、.resolve()和.reject() 4、.all()和.race()

在手撕Promise之前我们得先了解一下Promise的特性。
首先Promise本质就是一个构造函数,可以通过它创造Promise对象实例来实现异步编程的需求。
本篇文章我们需要实现的Promise特性如下:
JS深挖(手撕Promise详细代码完整攻略)
文章图片

1、new Promise((resolve,reject) => {})
作为一个构造函数,最先需要实现的是其基本的架构,我们先实现最基本的功能:
1)status存储状态、value和error存储成功/失败状态的值 2)resolve和reject方法改变状态 3)then方法实现状态改变后的回调

class MyPromise { constructor(executor) { this.status = 'pending'; this.value; // 成功状态的值 this.error; // 失败状态的值this.resolveCallbacks = []; this.rejectedCallbacks = []; let resolve = (res) => { }let reject = (err) => { }executor(resolve, reject) }then(onFulfilled, onRejected) { }catch() {} }

补充resolve和reject还有then和catch的内容
1)then最基本的功能就是状态改变后调用回调函数 2)catch本质就是只有失败状态的.then

class MyPromise { constructor(executor) { this.status = 'pending'; this.value; // 成功状态的值 this.error; // 失败状态的值this.resolveCallbacks = []; this.rejectedCallbacks = []; let resolve = (res) => { // 转变状态、执行回调 if (this.status === 'pending') { this.status = 'resolved'; this.value = https://www.it610.com/article/res; } }let reject = (err) => { // 转变状态、执行回调 if (this.status === 'pending') { this.status = 'rejected'; this.error = err; } }executor(resolve, reject) }then(onFulfilled, onRejected) { // 本质就是若当前状态为resolved或rejected 执行对应的回调函数 if (this.status === 'resolved') { onFulfilled(this.value); }if (this.status === 'rejected') { onRejected(this.error) } }catch(rejected) { return this.then(null, rejected) } }

这样我们就可以调用构造函数实现最基本的功能
let pro1 = new MyPromise((resolve, reject) => { resolve('成功了'); }).then(res => { console.log(res); })console.log(pro1); // 成功了

2、.then()及链式调用
上面then的写法存在几个问题:
1)当状态改变在异步函数中,此时执行.then无法立即执行回调,应该存储等待状态改变一起执行
2).then中的回调应该放在异步函数中,所以需要加setTimeout
3).then 返回值必须为Promise对象,所以每次异步处理的结果设为x,还需根据x决定返回的promise2的状态和值
这里引入resolvePromise方法决定返回的promise2的状态和值。
初步改进如下:
MyPromise.then(onFulfilled, onRejected) { // 本质就是若当前状态为resolved或rejected 执行对应的回调函数 let promise2; promise2 = new MyPromise((resolve, reject) => { if (this.status === 'resolved') { setTimeout(() => { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); }) }if (this.status === 'rejected') { setTimeout(() => { let x = onRejected(this.error); resolvePromise(promise2, x, resolve, reject); }) }if (this.status === 'pending') { this.resolveCallbacks.push(() => { setTimeout(() => { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); }) }); this.rejectedCallbacks.push(() => { setTimeout(() => { let x = onRejected(this.error); resolvePromise(promise2, x, resolve, reject); }) }); } })return promise2; }

函数resolvePromise的实现是Promise实现的核心,其内部包含几个重要的规则,简单概括:
1)若返回值x是数值,则返回fulfiiled状态的Promise,value为x
2)若返回值x是Promise对象,则继续递归调用
3)只有当返回值x为rejected状态的Promise对象,返回的才是失败状态的Promise
function resolvePromise(promise2, x, resolve, reject) { // 循环引用报错 if (x === promise2) { // reject 报错抛出 return reject(new TypeError('Chaining cycle detected for promise')); } // 锁,防止多次调用 let called; // x不是null 且x是对象或者函数 if (x != null && (typeof x === 'object' || typeof x === 'function')) { try { // A+ 规定,声明then = x的then方法 let then = x.then; // 如果then是函数,就默认是promise了 if (typeof then === 'function') { // 就让then执行 第一个参数是this后面是成功的回调 和 失败的回调 then.call(x, y => { // 成功和失败只能调用一个 if (called) return; called = true; // resolve的结果依旧是promise 那就继续递归执行 resolvePromise(promise2, y, resolve, reject); }, err => { // 成功和失败只能调用一个 if (called) return; called = true; reject(err); // 失败了就失败了 }) } else { resolve(x); // 直接成功即可 } } catch (e) { // 也属于失败 if (called) return; called = true; // 取then出错了那就不要在继续执行了 reject(e); } } else { resolve(x); } }

then实现的最后还需补充一些细节,比如传入的onFullfilled若不是函数,则忽略onFullfilled直接返回value;还有之前的resolve和reject加入回调数组的调用
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function' ? onRejected : error => error;

3、.resolve()和.reject()
Promise还可以直接调用resolve和reject方法,其本质就是new Promise然后改变状态。
MyPromise.resolve = (value) => { return new MyPromise((resolve, reject) => { resolve(value); }) }MyPromise.reject = (value) => { return new MyPromise((resolve, reject) => { reject(value); }) }

4、.all()和.race()
首先说说all()方法,其本质就是只有当参数里所有Promise对象都fulfilled才返回值,其有以下特性:
Promise.all([promise1,promise2,...])
1)仅在数组内所有promise对象都resolve,才resolve,且返回Promise对象,value是所有promise对象成功的value
2)如果有一个Promise对象reject,则返回第一个reject的promise结果
3)参数的promises只要求是可迭代对象,如果传递的不是Promise对象,则直接返回原值即可。
MyPromise.all = (promises) => { // promises是数组 if (!Array.isArray(promises)) { throw ('必须是数组') } let res = []return new MyPromise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { if (promises[i].then) { // 是promise对象则.then promises[i].then(r => { res.push(r); if (res.length === promises.length) { // 全部成功 return resolve(res); } }, error => { return reject(error); }) } else { // 不是promise对象则直接存value res.push(promises[i]); if (res.length === promises.length) { // 全部成功 return resolve(res); } } } }) }

race()方法与all相反,是只返回参数所有Promise对象最早改变状态的对象,其特性如下:
Promise.race(promises)
1)当数组中某一个Promise的状态变为fulfilled/rejected,则race返回那个Promise状态及value
2)直接把race的resolve注入到数组每个对象的回调中
MyPromise.race = (promises) => { return new MyPromise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then(resolve, reject); } }) }

【JS深挖(手撕Promise详细代码完整攻略)】所有Promise的手撕就完成了。

    推荐阅读