这一次,彻底弄懂 Promise 原理
作者声明
本人将迁移至个人公众号「前端Q」及「掘金」平台写文章。博客园的文章将不再及时更新发布。欢迎大家关注公众号「前端Q」及我的掘金主页:https://juejin.im/user/5874526761ff4b006d4fd9a4/posts
Promise 必须为以下三种状态之一:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。一旦Promise 被 resolve 或 reject,不能再迁移至其他任何状态(即状态 immutable)。
基本过程:
- 初始化 Promise 状态(pending)
- 执行 then(..) 注册回调处理数组(then 方法可被同一个 promise 调用多次)
- 立即执行 Promise 中传入的 fn 函数,将Promise 内部 resolve、reject 函数作为参数传递给 fn ,按事件机制时机处理
- Promise里的关键是要保证,then方法传入的参数 onFulfilled 和 onRejected,必须在then方法被调用的那一轮事件循环之后的新执行栈中执行。
真正的链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise.
链式调用
先从 Promise 执行结果看一下,有如下一段代码:
new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) resolve({ test: 2 }) reject({ test: 2 }) }, 1000) }).then((data) => { console.log('result1', data) },(data1)=>{ console.log('result2',data1) }).then((data) => { console.log('result3', data) }) //result1 { test: 1 } //result3 undefined
显然这里输出了不同的 data。由此可以看出几点:
- 可进行链式调用,且每次 then 返回了新的 Promise(2次打印结果不一致,如果是同一个实例,打印结果应该一致。
- 只输出第一次 resolve 的内容,reject 的内容没有输出,即 Promise 是有状态且状态只可以由pending -> fulfilled或 pending-> rejected,是不可逆的。
- then 中返回了新的 Promise,但是then中注册的回调仍然是属于上一个 Promise 的。
基于以上几点,我们先写个基于 PromiseA+ 规范的只含 resolve 方法的 Promise 模型:
function Promise(fn){ let state = 'pending'; let value = null; const callbacks = []; this.then = function (onFulfilled){ return new Promise((resolve, reject)=>{ handle({ //桥梁,将新 Promise 的 resolve 方法,放到前一个 promise 的回调对象中 onFulfilled, resolve }) }) } function handle(callback){ if(state === 'pending'){ callbacks.push(callback) return; } if(state === 'fulfilled'){ if(!callback.onFulfilled){ callback.resolve(value) return; } const ret = callback.onFulfilled(value) //处理回调 callback.resolve(ret) //处理下一个 promise 的resolve } } function resolve(newValue){ const fn = ()=>{ if(state !== 'pending')return state = 'fulfilled'; value = newValue handelCb() } setTimeout(fn,0) //基于 PromiseA+ 规范 } function handelCb(){ while(callbacks.length) { const fulfiledFn = callbacks.shift(); handle(fulfiledFn); }; } fn(resolve) }