对于手写 Promise,想必大家都非常相熟。基本上当初不论是大厂还是小厂,手写 promise 曾经成为了面试必考知识点。据说你还不太会?那么走着,带你从零开始解锁 Promise!

查看残缺代码请戳:github.com/qiruohan/article

常见 Promise 面试题

首先,咱们以常见的 Promise 面试题为切入点,咱们看看面试官们都爱考什么:

  1. Promise 解决了什么问题?
  2. Promise 的业界实现都有哪些?
  3. Promise 罕用的 API 有哪些?
  4. 能不能手写一个合乎 Promise/A+ 标准的 Promise?
  5. Promise 在事件循环中的执行过程是怎么的?
  6. Promise 有什么缺点,能够如何解决?

这几个问题由浅入深,咱们一个一个来看:

Promise 呈现的起因 & 业界实现

在 Promise 呈现以前,在咱们解决多个异步申请嵌套时,代码往往是这样的。。。

let fs = require('fs')fs.readFile('./name.txt','utf8',function(err,data){  fs.readFile(data, 'utf8',function(err,data){    fs.readFile(data,'utf8',function(err,data){      console.log(data);    })  })})

为了拿到回调的后果,咱们必须一层一层的嵌套,能够说是相当恶心了。而且基本上咱们还要对每次申请的后果进行一系列的解决,使得代码变的更加难以浏览和难以保护,这就是传说中臭名远扬的回调天堂

产生回调天堂的起因归纳起来有两点:

  1. 嵌套调用,第一个函数的输入往往是第二个函数的输出;
  2. 解决多个异步申请并发,开发时往往须要同步申请最终的后果。

起因剖析进去后,那么问题的解决思路就很清晰了:

  1. 毁灭嵌套调用:通过 Promise 的链式调用能够解决;
  2. 合并多个工作的申请后果:应用 Promise.all 获取合并多个工作的错误处理。

Promise 正是用一种更加敌对的代码组织形式,解决了异步嵌套的问题。

咱们来看看下面的例子用 Promise 实现是什么样的:

let fs = require('fs')function read(filename) {  return new Promise((resolve, reject) => {    fs.readFile(filename, 'utf8', (err, data) => {      if (err) reject(err);      resolve(data);    })  })}read('./name.txt').then((data)=>{  return read(data) }).then((data)=>{  return read(data)  }).then((data)=>{    console.log(data);},err=>{    console.log(err);})

臃肿的嵌套变得线性多了有木有?没错,他就是咱们的异步神器 Promise!

让咱们再次回归方才的问题,Promise为咱们解决了什么问题? 在传统的异步编程中,如果异步之间存在依赖关系,就须要通过层层嵌套回调的形式满足这种依赖,如果嵌套层数过多,可读性和能够维护性都会变得很差,产生所谓的“回调天堂”,而 Promise 将嵌套调用改为链式调用,减少了可浏览性和可维护性。也就是说,Promise 解决的是异步编码格调的问题。 那 Promise 的业界实现都有哪些呢? 业界比拟驰名的实现 Promise 的类库有 bluebird、Q、ES6-Promise。

从零开始,手写 Promise

Promise/A+

咱们想要手写一个 Promise,就要遵循 Promise/A+ 标准,业界所有 Promise 的类库都遵循这个标准。

其实 Promise/A+ 标准对如何实现一个符合标准的 Promise 类库曾经论述的很具体了。每一行代码在 Promise/A+ 标准中都有迹可循,所以在上面的实现的过程中,我会尽可能的将代码和 Promise/A+ 标准一一对应起来。

上面开始步入正题啦~

根底版 Promise

咱们先来回顾下最简略的 Promise 应用形式:

const p1 = new Promise((resolve, reject) => {  console.log('create a promise');  resolve('胜利了');})console.log("after new promise");const p2 = p1.then(data => {  console.log(data)  throw new Error('失败了')})const p3 = p2.then(data => {  console.log('success', data)}, err => {  console.log('faild', err)})

控制台输入:

"create a promise""after new promise""胜利了""faild Error: 失败了"
  • 首先咱们在调用 Promise 时,会返回一个 Promise 对象。
  • 构建 Promise 对象时,须要传入一个 executor 函数,Promise 的次要业务流程都在 executor 函数中执行。
  • 如果运行在 excutor 函数中的业务执行胜利了,会调用 resolve 函数;如果执行失败了,则调用 reject 函数。
  • Promise 的状态不可逆,同时调用 resolve 函数和 reject 函数,默认会采取第一次调用的后果。

以上简略介绍了 Promise 的一些次要的应用办法,联合 Promise/A+ 标准,咱们能够剖析出 Promise 的基本特征:

  1. promise 有三个状态:pendingfulfilled,or rejected;「标准 Promise/A+ 2.1」
  2. new promise时, 须要传递一个executor()执行器,执行器立刻执行;
  3. executor承受两个参数,别离是resolvereject
  4. promise 的默认状态是 pending
  5. promise 有一个value保留胜利状态的值,能够是undefined/thenable/promise;「标准 Promise/A+ 1.3」
  6. promise 有一个reason保留失败状态的值;「标准 Promise/A+ 1.5」
  7. promise 只能从pendingrejected, 或者从pendingfulfilled,状态一旦确认,就不会再扭转;
  8. promise 必须有一个then办法,then 接管两个参数,别离是 promise 胜利的回调 onFulfilled, 和 promise 失败的回调 onRejected;「标准 Promise/A+ 2.2」
  9. 如果调用 then 时,promise 曾经胜利,则执行onFulfilled,参数是promisevalue
  10. 如果调用 then 时,promise 曾经失败,那么执行onRejected, 参数是promisereason
  11. 如果 then 中抛出了异样,那么就会把这个异样作为参数,传递给下一个 then 的失败的回调onRejected

依照下面的特色,咱们试着勾画下 Promise 的形态:

// 三个状态:PENDING、FULFILLED、REJECTEDconst PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';class Promise {  constructor(executor) {    // 默认状态为 PENDING    this.status = PENDING;    // 寄存胜利状态的值,默认为 undefined    this.value = undefined;    // 寄存失败状态的值,默认为 undefined    this.reason = undefined;    // 调用此办法就是胜利    let resolve = (value) => {      // 状态为 PENDING 时才能够更新状态,避免 executor 中调用了两次 resovle/reject 办法      if(this.status ===  PENDING) {        this.status = FULFILLED;        this.value = value;      }    }     // 调用此办法就是失败    let reject = (reason) => {      // 状态为 PENDING 时才能够更新状态,避免 executor 中调用了两次 resovle/reject 办法      if(this.status ===  PENDING) {        this.status = REJECTED;        this.reason = reason;      }    }    try {      // 立刻执行,将 resolve 和 reject 函数传给使用者        executor(resolve,reject)    } catch (error) {      // 产生异样时执行失败逻辑      reject(error)    }  }  // 蕴含一个 then 办法,并接管两个参数 onFulfilled、onRejected  then(onFulfilled, onRejected) {    if (this.status === FULFILLED) {      onFulfilled(this.value)    }    if (this.status === REJECTED) {      onRejected(this.reason)    }  }}

写完代码咱们能够测试一下:

const promise = new Promise((resolve, reject) => {  resolve('胜利');}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

控制台输入:

"success 胜利"

当初咱们曾经实现了一个根底版的 Promise,然而还不要快乐的太早噢,这里咱们只解决了同步操作的 promise。如果在 executor()中传入一个异步操作的话呢,咱们试一下:

const promise = new Promise((resolve, reject) => {  // 传入一个异步操作  setTimeout(() => {    resolve('胜利');  },1000);}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

执行测试脚本后发现,promise 没有任何返回。

因为 promise 调用 then 办法时,以后的 promise 并没有胜利,始终处于 pending 状态。所以如果当调用 then 办法时,以后状态是 pending,咱们须要先将胜利和失败的回调别离寄存起来,在executor()的异步工作被执行时,触发 resolve 或 reject,顺次调用胜利或失败的回调。

联合这个思路,咱们优化一下代码:

const PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';class Promise {  constructor(executor) {    this.status = PENDING;    this.value = undefined;    this.reason = undefined;    // 寄存胜利的回调    this.onResolvedCallbacks = [];    // 寄存失败的回调    this.onRejectedCallbacks= [];    let resolve = (value) => {      if(this.status ===  PENDING) {        this.status = FULFILLED;        this.value = value;        // 顺次将对应的函数执行        this.onResolvedCallbacks.forEach(fn=>fn());      }    }     let reject = (reason) => {      if(this.status ===  PENDING) {        this.status = REJECTED;        this.reason = reason;        // 顺次将对应的函数执行        this.onRejectedCallbacks.forEach(fn=>fn());      }    }    try {      executor(resolve,reject)    } catch (error) {      reject(error)    }  }  then(onFulfilled, onRejected) {    if (this.status === FULFILLED) {      onFulfilled(this.value)    }    if (this.status === REJECTED) {      onRejected(this.reason)    }    if (this.status === PENDING) {      // 如果promise的状态是 pending,须要将 onFulfilled 和 onRejected 函数寄存起来,期待状态确定后,再顺次将对应的函数执行      this.onResolvedCallbacks.push(() => {        onFulfilled(this.value)      });      // 如果promise的状态是 pending,须要将 onFulfilled 和 onRejected 函数寄存起来,期待状态确定后,再顺次将对应的函数执行      this.onRejectedCallbacks.push(()=> {        onRejected(this.reason);      })    }  }}

测试一下:

const promise = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('胜利');  },1000);}).then(  (data) => {    console.log('success', data)  },  (err) => {    console.log('faild', err)  })

控制台期待 1s 后输入:

"success 胜利"

ok!功败垂成,异步问题曾经解决了!

相熟设计模式的同学,应该意识到了这其实是一个公布订阅模式,这种收集依赖 -> 触发告诉 -> 取出依赖执行的形式,被宽泛使用于公布订阅模式的实现。

then 的链式调用&值穿透个性

咱们都晓得,promise 的劣势在于能够链式调用。在咱们应用 Promise 的时候,当 then 函数中 return 了一个值,不论是什么值,咱们都能在下一个 then 中获取到,这就是所谓的then 的链式调用。而且,当咱们不在 then 中放入参数,例:promise.then().then(),那么其前面的 then 仍旧能够失去之前 then 返回的值,这就是所谓的值的穿透。那具体如何实现呢?简略思考一下,如果每次调用 then 的时候,咱们都从新创立一个 promise 对象,并把上一个 then 的返回后果传给这个新的 promise 的 then 办法,不就能够始终 then 上来了么?那咱们来试着实现一下。这也是手写 Promise 源码的重中之重,所以,打起精神来,重头戏来咯!

有了下面的想法,咱们再联合 Promise/A+ 标准梳理一下思路:

  1. then 的参数 onFulfilledonRejected 能够缺省,如果 onFulfilled 或者 onRejected不是函数,将其疏忽,且仍旧能够在上面的 then 中获取到之前返回的值;「标准 Promise/A+ 2.2.1、2.2.1.1、2.2.1.2」
  2. promise 能够 then 屡次,每次执行完 promise.then 办法后返回的都是一个“新的promise";「标准 Promise/A+ 2.2.7」
  3. 如果 then 的返回值 x 是一个一般值,那么就会把这个后果作为参数,传递给下一个 then 的胜利的回调中;
  4. 如果 then 中抛出了异样,那么就会把这个异样作为参数,传递给下一个 then 的失败的回调中;「标准 Promise/A+ 2.2.7.2」
  5. 如果 then 的返回值 x 是一个 promise,那么会等这个 promise 执行完,promise 如果胜利,就走下一个 then 的胜利;如果失败,就走下一个 then 的失败;如果抛出异样,就走下一个 then 的失败;「标准 Promise/A+ 2.2.7.3、2.2.7.4」
  6. 如果 then 的返回值 x 和 promise 是同一个援用对象,造成循环援用,则抛出异样,把异样传递给下一个 then 的失败的回调中;「标准 Promise/A+ 2.3.1」
  7. 如果 then 的返回值 x 是一个 promise,且 x 同时调用 resolve 函数和 reject 函数,则第一次调用优先,其余所有调用被疏忽;「标准 Promise/A+ 2.3.3.3.3」

咱们将代码补充残缺:

const PENDING = 'PENDING';const FULFILLED = 'FULFILLED';const REJECTED = 'REJECTED';const resolvePromise = (promise2, x, resolve, reject) => {  // 本人期待本人实现是谬误的实现,用一个类型谬误,完结掉 promise  Promise/A+ 2.3.1  if (promise2 === x) {     return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))  }  // Promise/A+ 2.3.3.3.3 只能调用一次  let called;  // 后续的条件要严格判断 保障代码能和别的库一起应用  if ((typeof x === 'object' && x != null) || typeof x === 'function') {     try {      // 为了判断 resolve 过的就不必再 reject 了(比方 reject 和 resolve 同时调用的时候)  Promise/A+ 2.3.3.1      let then = x.then;      if (typeof then === 'function') {         // 不要写成 x.then,间接 then.call 就能够了 因为 x.then 会再次取值,Object.defineProperty  Promise/A+ 2.3.3.3        then.call(x, y => { // 依据 promise 的状态决定是胜利还是失败          if (called) return;          called = true;          // 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1          resolvePromise(promise2, y, resolve, reject);         }, r => {          // 只有失败就失败 Promise/A+ 2.3.3.3.2          if (called) return;          called = true;          reject(r);        });      } else {        // 如果 x.then 是个一般值就间接返回 resolve 作为后果  Promise/A+ 2.3.3.4        resolve(x);      }    } catch (e) {      // Promise/A+ 2.3.3.2      if (called) return;      called = true;      reject(e)    }  } else {    // 如果 x 是个一般值就间接返回 resolve 作为后果  Promise/A+ 2.3.4      resolve(x)  }}class Promise {  constructor(executor) {    this.status = PENDING;    this.value = undefined;    this.reason = undefined;    this.onResolvedCallbacks = [];    this.onRejectedCallbacks= [];    let resolve = (value) => {      if(this.status ===  PENDING) {        this.status = FULFILLED;        this.value = value;        this.onResolvedCallbacks.forEach(fn=>fn());      }    }     let reject = (reason) => {      if(this.status ===  PENDING) {        this.status = REJECTED;        this.reason = reason;        this.onRejectedCallbacks.forEach(fn=>fn());      }    }    try {      executor(resolve,reject)    } catch (error) {      reject(error)    }  }  then(onFulfilled, onRejected) {    //解决 onFufilled,onRejected 没有传值的问题    //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;    //因为谬误的值要让前面拜访到,所以这里也要跑出个谬误,不然会在之后 then 的 resolve 中捕捉    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };    // 每次调用 then 都返回一个新的 promise  Promise/A+ 2.2.7    let promise2 = new Promise((resolve, reject) => {      if (this.status === FULFILLED) {        //Promise/A+ 2.2.2        //Promise/A+ 2.2.4 --- setTimeout        setTimeout(() => {          try {            //Promise/A+ 2.2.7.1            let x = onFulfilled(this.value);            // x可能是一个proimise            resolvePromise(promise2, x, resolve, reject);          } catch (e) {            //Promise/A+ 2.2.7.2            reject(e)          }        }, 0);      }      if (this.status === REJECTED) {        //Promise/A+ 2.2.3        setTimeout(() => {          try {            let x = onRejected(this.reason);            resolvePromise(promise2, x, resolve, reject);          } catch (e) {            reject(e)          }        }, 0);      }      if (this.status === PENDING) {        this.onResolvedCallbacks.push(() => {          setTimeout(() => {            try {              let x = onFulfilled(this.value);              resolvePromise(promise2, x, resolve, reject);            } catch (e) {              reject(e)            }          }, 0);        });        this.onRejectedCallbacks.push(()=> {          setTimeout(() => {            try {              let x = onRejected(this.reason);              resolvePromise(promise2, x, resolve, reject)            } catch (e) {              reject(e)            }          }, 0);        });      }    });      return promise2;  }}

测试一下:

const promise = new Promise((resolve, reject) => {  reject('失败');}).then().then().then(data=>{  console.log(data);},err=>{  console.log('err',err);})

控制台输入:

"失败 err"

至此,咱们曾经实现了 promise 最要害的局部:then 的链式调用和值的穿透。搞清楚了 then 的链式调用和值的穿透,你也就搞清楚了 Promise。

测试 Promise 是否符合规范

Promise/A+标准提供了一个专门的测试脚本,能够测试所编写的代码是否合乎Promise/A+的标准。

首先,在 promise 实现的代码中,减少以下代码:

Promise.defer = Promise.deferred = function () {  let dfd = {};  dfd.promise = new Promise((resolve,reject)=>{      dfd.resolve = resolve;      dfd.reject = reject;  })  return dfd;}

装置测试脚本:

npm install -g promises-aplus-tests

如果以后的 promise 源码的文件名为 promise.js

那么在对应的目录执行以下命令:

promises-aplus-tests promise.js

promises-aplus-tests 中共有 872 条测试用例。以上代码,能够完满通过所有用例。


感激小伙伴的揭示,因为文章中应用 setTimeout 实现 promise 的异步,会对大家造成误会。所以这里增加一些标注哈!

因为原生的 Promise 是V8引擎提供的微工作,咱们无奈还原V8引擎的实现,所以这里应用 setTimeout 模仿异步,所以原生的是微工作,这里是宏工作。

Promise A+ 标准3.1 中也提到了:

这能够通过“宏工作”机制(例如setTimeout或setImmediate)或“微工作”机制(例如MutatonObserver或)来实现process.nextTick。

如果你想实现 promise 的微工作,能够 mutationObserver 代替 seiTimeout 来实现微工作。

有小伙伴说能够应用 queueMicrotask 实现微工作,我也查阅了一些材料,是能够的。不过 queueMicrotask 兼容性不是很好,IE 下齐全不反对。据我所知 queueMicrotask 的 polyfill 是基于 promise 实现的,如果不反对 promise 会转成 setTimeout。

总的来说,queueMicrotask 和 mutationObserver 都能够实现微工作机制,不过更倡议有执念的小伙伴用 mutationObserver 实现一下,没有执念的小伙伴理解 promise 的微工作机制就好了~

Promise 的 API

尽管上述的 promise 源码曾经合乎 Promise/A+ 的标准,然而原生的 Promise 还提供了一些其余办法,如:

  • Promise.resolve()
  • Promise.reject()
  • Promise.prototype.catch()
  • Promise.prototype.finally()
  • Promise.all()
  • Promise.race()

上面具体说一下每个办法的实现:

Promise.resolve

默认产生一个胜利的 promise。

static resolve(data){  return new Promise((resolve,reject)=>{    resolve(data);  })}

这里须要留神的是,promise.resolve 是具备期待性能的。如果参数是 promise 会期待这个 promise 解析结束,在向下执行,所以这里须要在 resolve 办法中做一个小小的解决:

let resolve = (value) => {  // ======新增逻辑======  // 如果 value 是一个promise,那咱们的库中应该也要实现一个递归解析  if(value instanceof Promise){      // 递归解析       return value.then(resolve,reject)  }  // ===================  if(this.status ===  PENDING) {    this.status = FULFILLED;    this.value = value;    this.onResolvedCallbacks.forEach(fn=>fn());  }}

测试一下:

Promise.resolve(new Promise((resolve, reject) => {  setTimeout(() => {    resolve('ok');  }, 3000);})).then(data=>{  console.log(data,'success')}).catch(err=>{  console.log(err,'error')})

控制台期待 3s 后输入:

"ok success"

Promise.reject

默认产生一个失败的 promise,Promise.reject 是间接将值变成谬误后果。

static reject(reason){  return new Promise((resolve,reject)=>{    reject(reason);  })}

Promise.prototype.catch

Promise.prototype.catch 用来捕捉 promise 的异样,就相当于一个没有胜利的 then

Promise.prototype.catch = function(errCallback){  return this.then(null,errCallback)}

Promise.prototype.finally

finally 示意不是最终的意思,而是无论如何都会执行的意思。
如果返回一个 promise 会期待这个 promise 也执行结束。如果返回的是胜利的 promise,会采纳上一次的后果;如果返回的是失败的 promise,会用这个失败的后果,传到 catch 中。

Promise.prototype.finally = function(callback) {  return this.then((value)=>{    return Promise.resolve(callback()).then(()=>value)  },(reason)=>{    return Promise.resolve(callback()).then(()=>{throw reason})  })  }

测试一下:

Promise.resolve(456).finally(()=>{  return new Promise((resolve,reject)=>{    setTimeout(() => {        resolve(123)    }, 3000);  })}).then(data=>{  console.log(data,'success')}).catch(err=>{  console.log(err,'error')})

控制台期待 3s 后输入:

"456 success"

Promise.all

promise.all 是解决并发问题的,多个异步并发获取最终的后果(如果有一个失败则失败)。

Promise.all = function(values) {  if (!Array.isArray(values)) {    const type = typeof values;    return new TypeError(`TypeError: ${type} ${values} is not iterable`)  }    return new Promise((resolve, reject) => {    let resultArr = [];    let orderIndex = 0;    const processResultByKey = (value, index) => {      resultArr[index] = value;      if (++orderIndex === values.length) {          resolve(resultArr)      }    }    for (let i = 0; i < values.length; i++) {      let value = values[i];      if (value && typeof value.then === 'function') {        value.then((value) => {          processResultByKey(value, i);        }, reject);      } else {        processResultByKey(value, i);      }    }  });}

测试一下:

let p1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('ok1');  }, 1000);})let p2 = new Promise((resolve, reject) => {  setTimeout(() => {    reject('ok2');  }, 1000);})Promise.all([1,2,3,p1,p2]).then(data => {  console.log('resolve', data);}, err => {  console.log('reject', err);})

控制台期待 1s 后输入:

"resolve [ 1, 2, 3, 'ok1', 'ok2' ]"

Promise.race

Promise.race 用来解决多个申请,采纳最快的(谁先实现用谁的)。

Promise.race = function(promises) {  return new Promise((resolve, reject) => {    // 一起执行就是for循环    for (let i = 0; i < promises.length; i++) {      let val = promises[i];      if (val && typeof val.then === 'function') {        val.then(resolve, reject);      } else { // 一般值        resolve(val)      }    }  });}

特地须要留神的是:因为Promise 是没有中断办法的,xhr.abort()、ajax 有本人的中断办法,axios 是基于 ajax 实现的;fetch 基于 promise,所以他的申请是无奈中断的。

这也是 promise 存在的缺点,咱们能够应用 race 来本人封装中断办法:

function wrap(promise) {  // 在这里包装一个 promise,能够管制原来的promise是胜利还是失败  let abort;  let newPromise = new Promise((resolve, reject) => { // defer 办法      abort = reject;  });  let p = Promise.race([promise, newPromise]); // 任何一个先胜利或者失败 就能够获取到后果  p.abort = abort;  return p;}const promise = new Promise((resolve, reject) => {  setTimeout(() => { // 模仿的接口调用 ajax 必定有超时设置      resolve('胜利');  }, 1000);});let newPromise = wrap(promise);setTimeout(() => {  // 超过3秒 就算超时 应该让 proimise 走到失败态  newPromise.abort('超时了');}, 3000);newPromise.then((data => {    console.log('胜利的后果' + data)})).catch(e => {    console.log('失败的后果' + e)})

控制台期待 1s 后输入:

"胜利的后果胜利"

promisify

promisify 是把一个 node 中的 api 转换成 promise 的写法。
在 node 版本 12.18 以上,曾经反对了原生的 promisify 办法:const fs = require('fs').promises

const promisify = (fn) => { // 典型的高阶函数 参数是函数 返回值是函数   return (...args)=>{    return new Promise((resolve,reject)=>{      fn(...args,function (err,data) { // node中的回调函数的参数 第一个永远是error        if(err) return reject(err);        resolve(data);      })    });  }}

如果想要把 node 中所有的 api 都转换成 promise 的写法呢:

const promisifyAll = (target) =>{  Reflect.ownKeys(target).forEach(key=>{    if(typeof target[key] === 'function'){      // 默认会将原有的办法 全副减少一个 Async 后缀 变成 promise 写法      target[key+'Async'] = promisify(target[key]);    }  });  return target;}

小结

写了将近两万字,到这里,咱们终于能够给手写 promise 做一个结尾了。咱们先是从 promise 的应用办法动手,结构出了 promise 的大抵框架,而后依据 promise/A+ 标准填充代码,重点实现了 then 的链式调用和值的穿透;而后应用测试脚本对所写的代码是否符合规范进行了测试;最初实现了 Promise 的 API 的实现。弄懂 promise 其实并不简单,归根结底还是孰能生巧,没事还是要多加练习才行吖。

因为篇幅过长,所以这篇文章次要讲了面试题的1、2、3、4、6,对于第五点我会在讲 EventLoop 的文章中再进行零碎的梳理,置信在你看过 Promise 的源码之后,再了解 EventLoop,也会更加好了解了。

打算输入的相干内容文章:

  1. JS 的循环机制EventLoop(主线程、微工作、渲染、宏工作)。
  2. Generator/async+await 的实现。

如果你对我的文章感兴趣,欢送关注我噢!如果你对文章有任何的疑难,也欢送给我留言~

参考

9k字 | Promise/async/Generator实现原理解析

Promise之你看得懂的Promise

Promise的源码实现(完满合乎Promise/A+标准)

对于

作者齐小神,前端程序媛一枚。

有点文艺,喜爱摄影。尽管当初朝九晚五,埋头苦学,但幻想是做女侠,扶贫济穷,仗剑走咫尺。心愿有一天能改完 BUG 去实现本人的幻想。

公众号:大前端Space,不定时更新,欢送来玩~