Promise 实现 (从简易版到符合Promise A+规范)

前言

手写 Promise 是面试的时候大家都逃避的送命题,在学些了解后发现通过实现源码更能将新一代的异步方案理解的通透,知其然知其所以然的运用。

如果直接将源码贴到此处势必不能有更大的收获,下面就按实现版本来看做简要分析。

回顾 Promise

Promise 是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。

Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅,还可以批量处理异步任务。

简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1

三个状态:pending、fulfilled、rejected

两个过程:

  • pending → fulfilled(resolve)
  • pending → rejected(reject)

一个方法:then

当然还有其他概念,如 catch、 Promise.all/race/allSettled。

基础版

基础测试用例

// 1. 链式调用
var p1 = new Promise(function (resolve, reject) {console.log("init Promise");if (Math.random() > 0.5) {resolve("大");} else {reject("小");}
});
p1.then((data) => console.log("success", data),(reason) => console.log("error", reason)
).then(() => console.log("success 2"),() => console.log("error 2")
);

// 2. 异步延时
var sleep = (time, data) =>new Promise(function (resolve, reject) {setTimeout(resolve, time, data);});
sleep(3000, "时间到!").then((val) => {console.log(val);
});

// 3. 状态变更后不可变
const p2 = new Promise(function (resolve, reject) {resolve("失败了!");reject("还会成功吗!");
});
p2.then((data) => console.log(data),(reason) => console.log(reason)
);

// Promise 打印日志:
// init Promise
// success 大 / error 小
// 失败了!
// success 2 /error 2
// 时间到!(延时 3 s) 

Promise 的基本特征

1.new promise 时, 需要传入一个立即执行函数 fn,fn 接受两个参数,分别是 resolve 和 reject;
2.promise 有三个状态:pending,fulfilled,or rejected, 默认状态是 pending,只能从 pending 到 rejected, 或者从 pending 到 fulfilled,状态一旦确认,就不会再改变;
3.promise 必须有一个 then 方法,then 接收两个参数,分别是 promise 成功的回调 fulfilledFn, 和 promise 失败的回调 rejectedFn;
4.promise then 支持链式调用。

手写基础版

class Promise {constructor(executor) {this.status = "pending";this.handleFulfilled = []; // 存储成功后的回调this.handleRejection = []; // 存储失败后的回调// ! resolve 形参的实际参数在这儿const resolve = (data) => {// 状态变更只有一次if (this.status !== "pending") {return;}this.status = "fulfilled";// ! 等一会,否则 handleFulfilled 为空setTimeout(() => {this.handleFulfilled.forEach((fn) => fn(data));}, 0);};const reject = (reason) => {if (this.status !== "pending") {return;}this.status = "rejected";setTimeout(() => {this.handleRejection.forEach((fn) => fn(reason));}, 0);};try {executor(resolve, reject);} catch (e) {// 遇到错误时,捕获错误,执行 reject 函数reject(e);}}then(fulfilledFn, rejectedFn) {this.handleFulfilled.push(fulfilledFn);this.handleRejection.push(rejectedFn);return this;}
} 

测试用例:

// 简易版 Promise 打印日志:
// init Promise
// success 大 / error 小
// success 2 /error 2 (x 未通过)
// 失败了!
// 时间到!(延时 3 s) 

存在的问题:

1.微任务宏任务队列打印顺序
2.then 链式调用不是通过返回 this,而是返回一个新的 promise
3.链式调用支持参数缺省
4.等等…

认识 Promise /A+ 规范

手写 Promise,需要遵守怎样的规则,业界所有 Promise 的类库都遵循 Promise/A+ 规范。译文

改进版

先按 Promise 的基本规范对上面的基础版进行改进。

1.new promise 时, 需要传入一个立即执行函数executorexecutor 接受两个参数,分别是 resolve 和 reject;
2.promise 有三个状态:pendingfulfilled,or rejected, 默认状态是 pending,只能从 pendingrejected, 或者从 pendingfulfilled,状态一旦确认,就不会再改变;「规范 Promise/A+ 2.1」
3.promise 有一个value保存成功状态的值,可以是undefined/thenable/promise;「规范 Promise/A+ 1.3」
4.promise 有一个reason保存失败状态的值;「规范 Promise/A+ 1.5」
5.promise 必须有一个 then 方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值