6

如何手写一个Promise

 1 year ago
source link: https://nakeman.cn/blog/howto-write-promise-class/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如何手写一个Promise

经常听到有说要考验前端开发者的能力,让他手写一个promise,手写一个promise到底是什么意思?如果从编程解题,或编程技术 上看,“手写一个promise” 的使用什么编程技术 ,编程任务又是什么?

要回答这些问题,得先明白 promise 是什么。

promise对象 VS Promise API

首先明白,promise 这个字表达是一种概念,思想;在技术,有promise对象,和promise API 的不同。例如 JS 有一个 Promise类,也有返回 promise对象的API,例如 fetch。

promise是设计用来改善 原异步编程方式的,有一定前端开发经验的人一定明白 异步回调(callback),像定时器API:

setTimeout(() => saySomething("10 seconds passed"), 10 * 1000);

其实 promise对象 也是一种异步回调编程(工具),promise 背后也基于 callback 机制 ,只是对 原始 callback注1 进行逻辑封装,目的是为让「多步回调任务」流程更清晰,方便维护和异常处理。

手写promise的真正任务

从以上分析可看,“手写一个promise” 可以两层意思:第一,利用一个包装好的promise对象 进行异步业务编程;第二,是对原始的异步 callback进行包装,实现某种promise API。两个任务的性质完全 不一样,前者是一种业务编程,后者是一种功能(更底层)编程,要开发一个特别的类构函数(JS 已经提供了这个 Promise类)。

“手写一个promise” 指的应该是后一种编程任务,要求你 重写系统的Promise类。无论是哪一种编程,了解 promise异步业务逻辑 都是它们的基础。

其实还有第三种,就是用 系统的Promise 类 API(因为 Promise类只是个模板 )对一个原始异步操作进行包装,例如如下对 定时器 包装一个更具语义的 wait 异步函数:

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

wait(10 * 1000)
 .then(() => saySomething("10 seconds"))
 .catch(failureCallback);

promise异步业务流程

异步函数 和同步函数在语法上其实几乎是一样(例如函数作值的高阶函数),都有返回 值,和异常处理,只是在效果上,异步函数的执行有一定的延迟。再又,当异步返回值再用来调用另一个异步函数,原callback类 API 的代码 很难维护。

编程都有任务,达到一种功能 或效果 ,promise对象(及其模板类)的效果 就是让「多步回调任务」流程更清晰。这个效果 已经 被写成了规范——Promises/A+

规范比较长和繁琐,优化多步回调流程主要是两步:第一,将「原始异步操作」包括成一个 promise对象(类);第二,实现一种thenable 行为接口,将多个promise 串连起来。

原始异步操作的包装

1 类初始化对象时 发起异步操作(包括结果 的处理发起) 2 实例 then方法 对异步结果的处理

thenable与链式

then 方法 默认返回 一个新 promise对象

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});
promise.then(function(result) {
  console.log(result); // "Stuff worked!"
}, function(err) {
  console.log(err); // Error: "It broke"
});

研习手写promise的意义

现在(2023)async await已经相当成熟 了,研习 promise技术 还有意义 吗?其实还有,async await是基于 proimse的。意义主要有:

  • 1 更好使用promise工具 进行 异步业务编程(包括使用promise和包装一个原始异步操作)
  • 2 训练得更基础的 功能 编程 经验 (是个很好的例子)

1 reject 和 throw的区别

reject是 高级 自定义异常

2 自定义rejectHandler和 catch子句 用哪个

这里,“catch() 并没有任何特别之处,只是 then(undefined, func) 的添加剂,但它的可读性更好”

1 https://web.dev/promises/

2 https://www.sitepoint.com/overview-javascript-promises/


  1. 原始 callback api 是特殊 的API,利用事件队列实现的 异步API。promise对象 是对 原始 callback api的 逻辑封装

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK