Promise 你们都知道怎么用, 可是对于内部的原理不少人都不是很清楚 javascript
来看一个面试题: Promise的then 是怎么实现的java
首先来分析一下then面试
来一个一个看吧promise
Promise.prototype.then = function(){}
Promise.prototype.then = function(onFulfilled,onRejected){}
Promise.prototype.then = function(onFulfilled,onRejected){ return new Promise(function(resolve,reject){ // 代码省略 }) }
要实现promise链式 返回的必须是一个Promise 再因为status 改变状态了不能再变 因此须要第二个.... 第N个promise 调用新的resolve异步
Promise.prototype.then = function(onFulfilled,onRejected){ var self = this; // 保存当前上下文 return new Promise(function(resolve,reject){ if(self.status === 'resolved'){ onFulfilled(self.res) } if(self.status === 'rejected'){ onRejected(self.err) } }) }
Promise.resolve(res) 、、 同步代码的执行状况下 上述逻辑成立函数
res 跟err 来源以下this
function Promise(executor){ let self = this this.status = 'pending' // Promise 的状态值 this.res = undefined // 存成功以后的值 this.err = undefined // 存失败以后的值 executor(resolve,reject) // 省略代码 }
executor 有2个参数 分别为resolve,reject
当调用prototype
new Promise((resolve,reject)=>{ setTimeout(()=>{ if(true){ resolve('res') }else{ reject('err') } },1000) })
executor 会执行 而且把成功的值或者失败的值抛出来,resolve跟reject也是2个函数 定义在Promise内部线程
function Promise(executor){ // ...代码省略 function resolve(res){ self.res = res } function reject(err){ self.err = err } executor(resolve,reject) }
resolve 跟reject 还须要改变 Promise的状态值 而且一旦发生改变以后不能再次改变code
function Promise(executor){ // 代码省略 function resolve(res){ if(self.status === 'pending'){ self.status = 'resolved' self.res = res } } function reject(err){ if(self.status === 'pending'){ self.status = 'rejected' self.err = err } } executor(resolve,reject) }
咱们在executor中操做的每每是异步代码, 这个以后直接then, status的状态值并未发生改变, 因此不会执行onFulfilled跟onRejected,
这个时候咱们须要订阅
function Promise(executor){ // 代码省略 this.onFulfilledCallback = [] // 存成功以后的回调 this.onrejectedCallback = [] // 存失败以后的回调 function resolve(res){ if(self.status === 'pending'){ self.status = 'resolved' self.res = res } } function reject(err){ if(self.status === 'pending'){ self.status = 'rejected' self.err = err } } executor(resolve,reject) } new Promise(executor).then((onFulfilled,onrejected)=>{ var self = this; // 保存当前上下文 **注意: 第二次调用then this是指向new Promise的** return new Promise(function(resolve,reject){ // ...代码省略 if(self.status === 'pending'){ self.onFulfilledCallback.push(function(){ // 把成功以后须要作的事存起来 有多少个then就有多少个函数 onFulfilled(self.res) // 注意 这里的self.res 会随着then的调用发生改变 由于每次then都new 了一个Promise }) self.onrejectedCallback.push(function(){ // 把失败以后的事存起来 有多少个then就有多少个函数 onFulfilled(self.err) }) } }) })
当resolve的时候 或者reject的时候
一一拿出来执行
function resolve(res){ // 省略代码 self.res = res onFulfilledCallback.forEach(fn=>{ fn() }) }
实现链式调用咱们须要对then函数执行的返回值作一个操做!!!
需求:
Promise.prototype.then = function(onFulfilled,onRejected){ return new Promise((resolve,reject)=>{ // ...代码省略 if(self.status === 'resolved'){ let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行Promise.resolve() 同步代码 // 而后把x传递给下一个then resolve(x) } }) }
若是resolve是异步的话
Promise.prototype.then = function(onFulfilled,onRejected){ return new Promise((resolve,reject)=>{ // ...代码省略 if(self.status === 'resolved'){ let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行的是Promise.resolve() 同步代码 // 而后把x传递给下一个then resolve(x) } if(self.status === 'pending'){ self.onFulfilledCallback.push(function(){ let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 至关于 fn(){let x = onFulfilled} resolve(x) }) } }) } // 同时为了拿到 fn(){let x = onFulfilled ...} 得值 传递给下一个onFulfilled,onFulfilledCallback须要改写 onRejectedCallback同理 onFulfilledCallback.forEach(fn=>{ return fn() }) onRejectedCallback.forEach(fn=>{ return fn() })
-
考虑以下状况:
1. 返回值是个promise
Promsie.resolve(11).then(res=>{ return new Promise(executor) })
2. 返回值是个普通值
Promsie.resolve(11).then(res=>{ return 1 })
最关键的来了
咱们须要对onFullfillled 的返回值进行判断
修改then函数
// ...代码省略 if(self.status === 'resolved'){ let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行的是Promise.resolve() 同步代码 // 而后把x传递给下一个then promiseResolve(x,resolve,reject) }
function promiseResolve(x,resolve,reject){ if((typeof x != null && typeof x == 'object') || typeof x == 'function'){ // 肯定是个引用类型 if (x instanceof Promise){ // 肯定是个Promise 实例 let then = x.then then.call(x,res=>{ // 保证x调用res=>{}, res=>{}是then的onFulfilled方法 一直判断直到onFulfilled 返回的是个普通值 而后resolve出去 promiseResolve(res,resolve,reject) },err=>{ reject(err) }) } }else{ resolve(x) } }
考虑这样极端问题:
let p = new Promise(resolve=>{ resolve(3333) }) let p2 = p.then(resolve=>{ return p2 })
这样会出现什么问题呢, onFulfilled的返回结果若是是一个promise 上面的递归调用已经说明了 咱们要不断的去递归最终的onFulfilled结果 而后再改变p2的status 这样变成了p2去等待p2的执行结果 函数死掉了
因此onFulfilled的返回结果须要跟then的返回结果去比较 修改函数
function promiseResolve(x,resolve,reject,promise){ if(x === promise ){ return new Error('引用错误!') } if((typeof x != null && typeof x == 'object') || typeof x == 'function'){ // 肯定是个引用类型 if (x instanceof Promise){ // 肯定是个Promise 实例 let then = x.then then.call(x,res=>{ // 保证x调用res=>{}, res=>{}是then的onFulfilled方法 一直判断直到onFulfilled 返回的是个普通值 而后resolve出去 promiseResolve(res,resolve,reject) },err=>{ reject(err) }) } }else{ resolve(x) } }
Promise.prototype.then = function(onFulfilled,onRejected){ // ...代码省略 let promise2 = new Promise((resolve,reject)=>{ if(self.status === 'pending'){ self.onFulfilledCallback.push(function(){ let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 至关于 fn(){let x = onFulfilled} promiseResolve(x,resolve,reject,promise2) }) } }) return promise2 }
这段代码仍是有错误, 因为javascript主线程是单线程的, 因此在then里的promiseResolve是拿不到promise2的 因此咱们须要开启异步 使用定时器或者nextTick 这里咱们用定时器
Promise.prototype.then = function(onFulfilled,onRejected){ // ...代码省略 let promise2 = new Promise((resolve,reject)=>{ if(self.status === 'pending'){ self.onFulfilledCallback.push(function(){ setTimeout(()=>{ let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 至关于 fn(){let x = onFulfilled} promiseResolve(x,resolve,reject,promise2) },0) }) } }) return promise2 }
此时 整个then差很少完成了
then每次建立一个新的promise对象 对于同步的resolve,reject直接调用onFulfilled或者onRejected ,对于异步的resolve,reject使用
订阅发布模式,把每一个resolve,reject 暂存起来 等达到条件时候一一执行, 而且拿到返回结果去跟内部的promise比较,而且判断若是是一个promise的话,不断解析onFulfilled 的返回结果 直至resolve出去