前言
promise的实现主要有三步:
一.实现原型调用
二.解决异步调用
三.解决链式调用
实现原型调用
首先明确我们的需求:promise的基本使用为:
let p2 = new Promise((res, rej) => { res() }) p2.then(() => { console.log('resolve then'); })
复制代码
根据以上基本用法,我们知道我们需要实现的类具有具有以下特点:
- 具有绑定在原型链上的then函数
- 声明参数为一个具有resolve跟reject函数的立即执行函数
故可以得出以下代码:
let MPromise = function (excute) { let status = 'pending' // 初始化promise状态 let resolve = () => { if (status == 'pending') { // 不可逆原则, this.status = 'resolve' } } let reject = () => { if (status == 'pending') { this.status = 'reject' } } excute(resolve, reject) } MPromise.prototype.then = function (resolve, reject) { //在其原型链上绑定then函数 let self = this if (self.status == 'resolve') { resolve() } if (self.status == 'reject') { reject() } }复制代码
调用我们的MPromise
let p = new MPromise((res, rej) => { console.log('start'); rej() console.log('end'); }) p.then(function () { console.log('then resolve'); }, function () { console.log('then reject'); })复制代码
输出:
由此我们初步的promise原型已经完成。
2. 解决异步调用
先看看原生Promise对异步事件的处理:
let p2 = new Promise((res, rej) => { console.log('befor'); setTimeout(function(){ res() }) console.log('after'); }) p2.then(() => { console.log('resolve then'); })复制代码
输出:
befor
after
resolve then
而在上一步完成的MPromise没用加入异步事件的处理,在遇到异步事件时并不会执行res。
let p = new MPromise((res, rej) => { console.log('start'); setTimeout(function(){ res() }) console.log('end'); }) p.then(function () { console.log('then resolve'); }, function () { console.log('then reject'); })复制代码
输出为:
start
end
造成异步事件中的res没有执行的原因是由于js的事件机制造成的,异步事件会在同步事件执行完毕后才执行,也就是res()中改变thi.state是在then函数执行后再执行,所以造成了then在判断state的状态时无法正确处理。解决方法的主要思想是加入数组暂存,如下:
let MPromise = function (excute) { this.status = 'pending' this.resolvArray = [] this.rejectArray = [] this.value = undefined this.reason = undefined let resolve = (value) => { if (this.status == 'pending') { this.status = 'resolve' this.value = value this.resolvArray.forEach(fun => { // 执行暂存中的函数 fun() }); } } let reject = (reason) => { if (this.status == 'pending') { this.reason = reason this.status = 'reject' this.rejectArray.forEach(fun => { fun() }); } } excute(resolve, reject) } MPromise.prototype.then = function (resolve, reject) { let self = this if (self.status == 'resolve') { resolve(this.value) } if (self.status == 'reject') { reject(this.reason) } if (self.status == 'pending') { // 如果为pending则将resolve跟rejectpush到其对应暂存数组中 self.resolvArray.push( function () { resolve(self.value) }) self.rejectArray.push( function () { reject(self.reason) }) } }复制代码
测试我们的MPromise
let p = new MPromise((res, rej) => { console.log('start'); setTimeout(function () { res('param') }, 2000) console.log('end'); }) p.then(function (val) { console.log('then resolve' + val); }, function (val) { console.log('then reject' + val); }) 复制代码
3. 解决链式调用
最后一步,promise最重要的作用:链式调用解决回调地狱。核心思想:在then中返回一个新的promise实例:
MPromise.prototype.then = function (onResolve, onReject) { let self = this let p2 = new MPromise((resolve, reject) => { if (self.status == 'resolve') { try { let x = onResolve(self.value) resolve(x) // 这是 x 是常量的时候,但x可能是一个新的promise, } catch (e) { reject(e) } // resolve(this.value) } if (self.status == 'reject') { try { let x = onReject(self.reason) resolve(x) } catch (e) { reject(e) } } if (self.status == 'pending') { self.resolvArray.push( function () { try { let x = onResolve(self.value) resolve(x) } catch (e) { reject(e) } }) self.rejectArray.push( function () { try { let x = onReject(self.reason) resolve(x) } catch (e) { reject(e) } }) } }) return p2 }复制代码
测试我们的代码:
let p = new MPromise((res, rej) => { console.log('start'); // setTimeout(function () { res('param') // }, 2000) }) let p2 = p.then(function (val) { console.log('then resolve' + val); }, function (val) { console.log('then reject' + val); }) p2.then((val)=>{ console.log('second then '+val); },()=>{ }).then((val)=>{ console.log('three then '+val); },()=>{ }) console.log(p2); console.log('end');复制代码
输出:
start
end
then resolveparam
second then
three then
结语
promise的核心思想为如上的三步,理解后就很简单。