先贴出关键代码,分析如下
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class Promisee { constructor(handle) { // 添加成功回调函数队列 this._fulfilledQueue = [] // 添加失败回调函数队列 this._rejectedQueue = [] this._value = null this._status = PENDING try { handle(this._resolve.bind(this), this._reject.bind(this)) } catch (e) { //TODO handle the exception } } _resolve(val) { if (this._status !== PENDING) return this._status = FULFILLED let cb const runFulfilled = (value) => { let cb; while (cb = this._fulfilledQueue.shift()) { cb(value) } } // 依次执行失败队列中的函数,并清空队列 const runRejected = (error) => { let cb while (cb = this._rejectedQueue.shift()) { cb(error) } } /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后, 当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态 */ if (val instanceof Promisee) { val.then(value => { this._value = value runFulfilled(value) }, err => { this._value = err runRejected(err) }) } else { this._value = val runFulfilled(val) } } _reject() { } then(onFulfilled, onRejected) { //第一个zhen的cb函数会放在第二个promise里面执行 //执行handle,并且把执行结果给第二个then,并执行第二个then的resolve函数 return new Promisee((onFulfilledNext, onRejectedNext) => { //执行函数,并把执行结果给下一个promise的resolve //由于该函数是异步的,所以会执行第二个zhen函数,此时的status为pending let fulfilled = (value) => { setTimeout(() => { console.log(5) //onFulfilled第一个zhen的回调函数 //onFulfilledNext下一个zhen的resolve函数 let res = onFulfilled(value) if (res instanceof Promisee) { // 如果当前回调函数返回Promisee对象,必须等待其状态改变后在执行下一个回调 res.then(onFulfilledNext, onRejectedNext) } else { // 否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数 onFulfilledNext(res) } }, 0) } switch (this._status) { // 当状态为pending时,将then方法回调函数加入执行队列等待执行 case PENDING: console.log(2) // debugger this._fulfilledQueue.push(fulfilled) this._rejectedQueue.push(rejected) break // 当状态已经改变时,立即执行对应的回调函数 //第一次来到这里,this为前一个promise case FULFILLED: console.log(1) fulfilled(this._value) break case REJECTED: rejected(this._value) break } }) } // 添加静态resolve方法 static resolve(value) { return value instanceof Promisee || (value && isFunction(value.then)) ? value : new Promisee(resolve => resolve(value)) } } //执行顺序为125453 //执行完handle函数后执行then函数 let p = new Pomisee((res, rej) => { res(123) }).then((res, rej) => { console.log(4) // console.log(res) return res+11111 }).then(res=>{ console.log(res) })以上代码是简化版的Promise,本人就此代码来说明Promise为什么支持链式调用
可以看到在new Promise的时候会把里面的cb传给handle,而handle函数会传入两个参数,这两个参数一个是resolve,一个就是reject。并且会立即执行cb,从而执行resolve函数并把123传过去,此时由于没有调用then函数,所以待执行数组中是空,但是会保存value(123),以上就是new Promise时所做的
try { handle(this._resolve.bind(this), this._reject.bind(this)) } catch (e) { //TODO handle the exception }执行完new Promise后调用then函数,此时zhen函数的cb就是onFulfilled。then函数返回一个Promise对象,该Promise对象是为了链式调用而准备的,是给下一个then函数调用的。所以第一个then函数执行无须关注,只要注意到在该函数内传入的会立即执行的代码fulfilled和switch,此时的this指的是p,p由于已经执行了resolve函数,所以状态为FULFILLED,随后执行fulfilled(this._value),该函数为异步函数,所以不会立即执行,而是在下一次循环前执行。此时会接着执行第二个then函数,第二个zhen函数来源于第一个then函数返回的Promise对象,所以第二个then函数没有执行过resolve函数,status为PENDING,会走switch的第一个,将cb2放入回调数组里,此时第二个then执行完毕。然后继续回到第一个then的setTimeout里执行,此时执行onFulfilled(value),是第一个then的cb,传入123,由于返回不是promise所以会执行onFulfilledNext(res),这个onFulfilledNext是下一个then函数的resolve,通过调用该函数可以将第一个then函数传给第二个then,此时执行第二个then的resolve,遍历并执行回调数组,此时第二个then函数执行完毕。
let fulfilled = (value) => { setTimeout(() => { console.log(5) //onFulfilled第一个zhen的回调函数 //onFulfilledNext下一个zhen的resolve函数 let res = onFulfilled(value) if (res instanceof Promisee) { // 如果当前回调函数返回Promisee对象,必须等待其状态改变后在执行下一个回调 res.then(onFulfilledNext, onRejectedNext) } else { // 否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数 onFulfilledNext(res) } }, 0) } switch (this._status) { // 当状态为pending时,将then方法回调函数加入执行队列等待执行 case PENDING: console.log(2) // debugger this._fulfilledQueue.push(fulfilled) this._rejectedQueue.push(rejected) break // 当状态已经改变时,立即执行对应的回调函数 //第一次来到这里,this为前一个promise case FULFILLED: console.log(1) fulfilled(this._value) break case REJECTED: rejected(this._value) break } })总结: 1.为什么要先执行resolve函数? 之所以执行resolve函数是要告诉下一个then函数我已经执行完毕,可以调用回调了,不执行resolve是不会执行回调函数的 2.为什么then函数是异步的? 首先方便then函数里面可以放耗时较长的操作,以免影响到同步代码执行 其次是为了链式调用,从上面的分析可以看出第一个then函数的setTimeout不会立即执行,而是等下一次循环前执行,这样一来第二个then就会在第一个then函数的setTimeout之前执行,从而加入回调数组。此时setTimeout再执行就可以将回调结果给第二个then,节省了不少代码。 3.第一个then先执行完毕然后再执行第二个then吗? 不是,第一个then是异步的,第一个zhen执行到异步函数后才会执行第二个then,然后又返回去执行第一个then。 4.链式调用是怎么保证按顺序执行? 第二个then的resolve函数会在第一个then的cb执行完成后再调用resolve,从而保证顺序执行,而第二个then函数的cb也会在第一个then函数setTimeout执行前放入回调数组里(异步调用的好处)