下一个泡泡玛特工程师是谁呢?

收集一些自己用到的prompt

2023-04-05 · 1 min read

机械键盘相关参数

机械键盘相关参数记录

2023-04-05 · 1 min read

Web 前端性能优化

常用的web前端性能优化手段

2023-03-19 · 3 min read

Blender常用快捷键

自己经常用到的一些快捷键记录

2022-12-11 · 1 min read

Docker 常用命令

精简 Docker 常用命令

2022-11-06 · 1 min read

项目管理

项目管理相关知识

2022-11-06 · 1 min read

JS沙箱sandbox的各种实现

我们把Js隔离机制常常称作沙箱

2022-09-18 · 1 min read

Amazing!Solid 比react还react

今天来介绍2个amazing的东东

2022-09-12 · 1 min read

puppeteer应用

使用傀儡师来操作浏览器这个傀儡吧

2022-09-11 · 1 min read

做一个web termianl

前端react, 后端nodejs, 直接可用版web termianl

2022-07-17 · 1 min read

TypeScript里常用的工具类型

经常用到的工具类型,提取抽离出来,供以后复用

2022-06-26 · 1 min read

Vim大法好

想要丢掉鼠标,试试Vim

2022-06-26 · 1 min read

碧血丹心

无论时光如何沾染风霜,也永似红日光

2022-05-10 · 1 min read

chrome V8 引擎中的垃圾回收机制

V8引擎就是nodejs的发动机

2022-03-03 · 1 min read

如何开发一个cli

命令行交互界面是程序员必备的工具,如何开发一个呢?

2022-02-21 · 1 min read

Javascript中的哲学

道生一,一生二,二生三,三生万物

2022-02-20 · 1 min read

React Redux 实现 (Context 版)

React Redux 实现 (Context 版)

2022-02-16 · 1 min read

mobx-react 使用

虽然不常用,但是可以学一下

2022-02-16 · 1 min read

Less中的for和forEach循环

循环的使用是保持代码干燥和避免重复的好方法

2022-02-15 · 1 min read

Webpack Splitchunks 详解

webpack 优化

2022-02-15 · 1 min read

ssh-keygen命令详解

为ssh生成、管理和转换认证密钥

2022-02-15 · 1 min read

使用CURL发送POST请求

curl 是常用的命令行工具,用来请求 Web 服务器。

2022-02-15 · 1 min read

Webpack Plugin 开发

让我们来学一下如何开发一个webpack插件

2022-02-14 · 1 min read

JS 实现两个大数相加?

algo-adding-large-numbers

2022-02-10 · 1 min read

字典树 trie

字典树 trie

2022-02-09 · 1 min read

浏览器原理问题

浏览器原理问题

2022-01-11 · 1 min read

MacBook快速进入一个文件夹目录

mac如何快速进入一个文件夹

2021-10-26 · 1 min read

react合成事件

react-synthetic-event

2021-10-25 · 1 min read

mini webpack实现

通过babel核心来实现迷你版的webpack

2021-10-10 · 1 min read

设计模式

在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于类

2021-10-10 · 1 min read

babel核心

babel核心介绍

2021-10-07 · 1 min read

React 15 和 React 16 的区别

react-15-16

2021-10-06 · 1 min read

React性能优化

浅谈react性能优化的方法

2021-10-05 · 1 min read

交通信号灯实现

如何用js来实现交通信号灯呢

2021-09-25 · 1 min read

内存管理

前端中的内存管理

2021-09-25 · 1 min read

前端安全

前端关于安全方面的知识

2021-09-25 · 2 min read

网络和并发

http各版本对于并发的支持,前端如何控制并发量?

2021-09-25 · 1 min read

跨域方法

总结了9种跨域方法

2021-09-24 · 1 min read

react virtualList 虚拟列表无限滚动实现

用react实现虚拟滚动

2021-09-16 · 1 min read

监控埋点方案

前端监控埋点方案

2021-09-16 · 1 min read

Mini useEffect实现

如何实现useEffect?

2021-09-11 · 1 min read

Mini useState 实现

我们来思考一下useState是怎么实现的呢?

2021-09-11 · 1 min read

React Fiber

react-fiber

2021-09-11 · 1 min read

React class组件和function组件异同

类组件和函数组件有何相同点有何不同点呢?

2021-09-11 · 1 min read

Lodash Get 实现

algo-lodash-get

2021-09-08 · 1 min read

手写reduce实现

algo-reduce

2021-09-08 · 1 min read

Hooks 原理概览

react-hooks

2021-09-05 · 1 min read

Hook原理——状态Hook

react-hook-state

2021-09-05 · 1 min read

手写Mini Redux实现

手写一个简易版的redux实现,包含了核心逻辑

2021-09-04 · 1 min read

legacy和concurrent模式

react-legacy-concurrent

2021-09-01 · 1 min read

react架构

总体 react 的核心可以用 ui=fn(state)来表示 3 大核心对象、3 大核心阶段、2 大工作循环 Scheduler(调度器): 排序优先级,让优先级高的任务先进行 reconcile Reconciler…

2021-09-01 · 2 min read

react核心api和jsx

为什么要有jsx,为什么会有虚拟bom

2021-09-01 · 1 min read

setState是同步的还是异步的

react-setstate-usestate

2021-08-31 · 1 min read

如何使用NodeJs创建HTTP服务?

如何使用NodeJs创建HTTP服务?

2021-08-17 · 1 min read

NodeJS 事件循环模型

nodejs-eventloop

2021-08-11 · 2 min read

Buffer

nodejs中的内存管理

2021-08-10 · 1 min read

微前端解决方案-qiankun

目前国内最好的微前端解决方案-qiankun

2021-08-10 · 1 min read

React Mini版实现(1)

学一门技术最好的方法就是做一个其玩具版的实现,我们来尝试实现一下react和react-dom最简单版本吧

2021-08-04 · 1 min read

brew安装

brew 是 MacOS 上的包管理工具,可以简化 macOS 和 Linux 操作系统上软件的安装。

2021-08-04 · 1 min read

CommonJS简易版实现

CommonJS我们经常用,如何实现一个简易版的commonJS呢?

2021-08-01 · 1 min read

极品透明Dashboard样式分享

一个极品透明Dashboard样式分享

2021-07-30 · 1 min read

Stream

nodejs中的流

2021-07-11 · 1 min read

NodeJS全局对象

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

2021-05-18 · 1 min read

如何部署Nodejs服务

如何快速的部署一个Nodejs服务到公网呢?

2021-05-12 · 1 min read

Events

events模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http、fs等。

2021-05-11 · 1 min read

用JS绘制背景,让CSS直接使用 'background:paint(xxx)'

CSS对象新特性,新的background设置方式

2021-04-30 · 1 min read

Block Formatting Context 块级格式化上下文

可以将BFC看成是元素的一种属性,拥有了这种属性的元素就会使他的子元素与世隔绝,不会影响到外部其他元素

2021-04-17 · 1 min read

如何使用Nodejs来创建一个TCP/UDP服务?

如何使用Nodejs来创建一个TCP/UDP服务?

2021-04-17 · 1 min read

Mac使用tree生成目录结构

程序员经常会有需求,需要列出项目的结构树。Mac或者Linux下可以使用tree列出项目结构

2021-04-04 · 1 min read

常见算法

一些比较常见算法

2021-03-20 · 1 min read

前端缓存

对于性能优化离不开缓存

2021-02-28 · 1 min read

前端答疑

一些比较常见的问题

2020-09-02 · 1 min read

Nodejs 网络 & HTTP

nodejs-network

2020-08-14 · 1 min read

JavaScript AST 抽象语法树

源代码的抽象语法结构的树状表现形式

2020-08-02 · 1 min read

nodejs里面向切面编程的一种范式

在一些场景下我们可能需要一种面向切面的编程方式

2020-08-01 · 1 min read

各种JS模块化特性

AMD、CMD、CJS、ESM

2020-05-30 · 1 min read

手写Ajax实现

使用HMR一步步实现Ajax

2020-05-30 · min read

手写PromiseA+实现

如何自己实现promiseA+规范,手写一个promise实现

2020-04-30 · 1 min read

debug和内存泄露

nodejs的debug方法

2020-04-08 · 1 min read

Javascript prototype 原型链

js-prototype

2019-09-07 · 1 min read

this指针、作用域

this是在执行时动态读取上下文决定的,不是在定义时决定

2019-06-14 · 1 min read

call、apply、bind的极简实现

使用symbol实

2019-06-03 · 1 min read

CSS联合选择器区分列表元素个数不同所要求的不同样式

对于列表,在有些时候针对于不同个数的item会有不同的显示,比如col份数,用js固然可以,是否可以用css更简便的实现呢?

2019-04-30 · 1 min read

TypeScript基础

介绍TypeScript基础知识

2019-04-30 · 1 min read

JS中的变量提升

为什么js当时要这样设计

2019-03-07 · 1 min read

ES6之Class

关于ES6里的class, 我们有什么不知道的事?

2019-03-01 · 1 min read

HTTP详解

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议

2019-02-17 · 2 min read

极简代码实现节流Throttle和防抖Debounce

使用各9行代码实现节流和防抖函数

2019-01-30 · 1 min read

Javascript 事件循环 EventLoop

js-eventloop

2018-09-07 · 1 min read

POST和GET区别

POST和GET区别是什么呢?

2018-08-14 · 1 min read

正则表达式

正则表达式一锅端

2018-07-30 · 1 min read

cloneDeep 深克隆实现

algo-clonedeep

2017-09-07 · 1 min read

webpack

engin-webpack

2017-09-07 · 1 min read

http1.1和http2.0有什么区别

http1.1和http2.0有什么区别

2017-06-14 · 1 min read

手写EventEmitter事件巴士

咱们来手写实现一个EventEmitter事件巴士

2017-01-10 · 1 min read

OOP 面向对象编程

对象是什么?为什么要面向对象?

2016-05-08 · 1 min read
Stay hungry & Stay foolish
战歌
16
The Reluctant Warrior
Immediate Music
To Glory
Two Steps From Hell
Victory
Two Steps From Hell
Empire of Angels
Thomas Bergersen
Serenata Immortale
Immediate Music
Cornfield Chase
Hans Zimmer
Tennessee
Hans Zimmer
He's a Pirate
Martin Ermen
Rise
Hans Zimmer
On Thin Ice
Hans Zimmer
Angels Will Rise
Twisted Jukebo
When It All Falls Down
Audiomachine
Icarus
Ivan Torrent
Star Sky - Instrumental
Two Steps From Hell
亡灵序曲
L
Up Is Down
Hans Zimm
回到首页

手写PromiseA+实现

袁官东
April 30th, 2020 · 1 min read
图:Nguyen Nhut

1、使用class

平常用 promise 的时候, 是通过 new 关键字来 new Promise(), 所以咱们应该用构造函数或者 class 来实现. 都 2021 年了, 咱们就用 class 来实现一下吧.

1class MPromise {
2 constructor() {}
3}

2. 定义三种状态类型

1const PENDING = "pending";
2const FULFILLED = "fulfilled";
3const REJECTED = "rejected";

3. 设置初始状态

1class MPromise {
2 constructor() {
3 // 初始状态为pending
4 this.status = PENDING;
5 this.value = null;
6 this.reason = null;
7 }
8}

4. resolve 和 reject 方法

4.1. 根据A+的规范, 这两个方法是要更改 status 的, 从 pending 改到 fulfilled/rejected. 4.2. 注意两个函数的入参分别是 value 和 reason.

1class MPromise {
2 constructor() {
3 // 初始状态为pending
4 this.status = PENDING;
5 this.value = null;
6 this.reason = null;
7 }
8
9 resolve(value) {
10 if (this.status === PENDING) {
11 this.value = value;
12 this.status = FULFILLED;
13 }
14 }
15
16 reject(reason) {
17 if (this.status === PENDING) {
18 this.reason = reason;
19 this.status = REJECTED;
20 }
21 }
22}

5. promise入参

5.1. 入参是一个函数, 函数接收 resolve 和 reject 两个参数. 5.2. 注意在初始化 promise 的时候, 就要执行这个函数, 并且有任何报错都要通过 reject 抛出去

1class MPromise {
2 constructor(fn) {
3 // 初始状态为pending
4 this.status = PENDING;
5 this.value = null;
6 this.reason = null;
7
8 try {
9 fn(this.resolve.bind(this), this.reject.bind(this));
10 } catch (e) {
11 this.reject(e);
12 }
13 }
14
15 resolve(value) {
16 if (this.status === PENDING) {
17 this.value = value;
18 this.status = FULFILLED;
19 }
20 }
21
22 reject(reason) {
23 if (this.status === PENDING) {
24 this.reason = reason;
25 this.status = REJECTED;
26 }
27 }
28}

6. then 方法

6.1. then 接收两个参数, onFulfilled 和 onRejected

1then(onFulfilled, onRejected) {}

6.2. 检查并处理参数, 之前提到的如果不是 function, 就忽略. 这个忽略指的是原样返回 value 或者 reason.

1isFunction(param) {
2 return typeof param === 'function';
3}
4
5then(onFulfilled, onRejected) {
6 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
7 return value
8 }
9 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
10 throw reason;
11 };
12}

6.3. 要知道.then 的返回值整体是一个 promise, 所以咱们先用 promise 来包裹一下, 其他逻辑待会再实现.

1then(onFulfilled, onRejected) {
2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
3 return value
4 }
5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
6 throw reason;
7 };
8 const promise2 = new MPromise((resolve, reject) => {})
9 return promise2
10}

6.4. 根据当前 promise 的状态, 调用不同的函数

1then(onFulfilled, onRejected) {
2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
3 return value
4 }
5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
6 throw reason;
7 };
8 const promise2 = new MPromise((resolve, reject) => {
9 switch (this.status) {
10 case FULFILLED: {
11 realOnFulfilled()
12 break;
13 }
14 case REJECTED: {
15 realOnRejected()
16 break;
17 }
18 }
19 })
20 return promise2
21
22}

6.5. 这样写, 是在 then 函数被调用的瞬间就会执行. 那这时候如果 status 还没变成 fulfilled 或者 rejected 怎么办, 很有可能还是 pending 的. 所以我们需要一个状态的监听机制, 当状态变成 fulfilled 或者 rejected 后, 再去执行 callback.

6.5.1. 那么我们首先要拿到所有的 callback, 然后才能在某个时机去执行他. 新建两个数组, 来分别存储成功和失败的回调, 调用 then 的时候, 如果还是 pending 就存入数组.

1FULFILLED_CALLBACK_LIST = [];
2REJECTED_CALLBACK_LIST = [];
3
4then(onFulfilled, onRejected) {
5const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
6 return value
7}
8const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
9 throw reason;
10};
11const promise2 = new MPromise((resolve, reject) => {
12 switch (this.status) {
13 case FULFILLED: {
14 realOnFulfilled()
15 break;
16 }
17 case REJECTED: {
18 realOnRejected()
19 break;
20 }
21 case PENDING: {
22 this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
23 this.REJECTED_CALLBACK_LIST.push(realOnRejected)
24 }
25 }
26})
27return promise2
28
29}

6.5.2. 在 status 发生变化的时候, 就执行所有的回调. 这里咱们用一下 es6 的 getter 和 setter. 这样更符合语义, 当 status 改变时, 去做什么事情. (当然也可以顺序执行, 在给 status 赋值后, 下面再加一行 forEach)

1_status = PENDING;
2
3get status() {
4 return this._status;
5}
6
7set status(newStatus) {
8 this._status = newStatus;
9 switch (newStatus) {
10 case FULFILLED: {
11 this.FULFILLED_CALLBACK_LIST.forEach(callback => {
12 callback(this.value);
13 });
14 break;
15 }
16 case REJECTED: {
17 this.REJECTED_CALLBACK_LIST.forEach(callback => {
18 callback(this.reason);
19 });
20 break;
21 }
22 }
23}

7. then 的返回值

上面只是简单说了下, then 的返回值是一个 Promise, 那么接下来具体讲一下返回 promise 的 value 和 reason 是什么.

7.1. 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动 catch 代码,遇到报错就 reject)

1then(onFulfilled, onRejected) {
2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
3 return value
4 }
5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
6 throw reason;
7 };
8 const promise2 = new MPromise((resolve, reject) => {
9 const fulfilledMicrotask = () => {
10 try {
11 realOnFulfilled(this.value);
12 } catch (e) {
13 reject(e)
14 }
15 };
16 const rejectedMicrotask = () => {
17 try {
18 realOnRejected(this.reason);
19 } catch (e) {
20 reject(e);
21 }
22 }
23
24 switch (this.status) {
25 case FULFILLED: {
26 fulfilledMicrotask()
27 break;
28 }
29 case REJECTED: {
30 rejectedMicrotask()
31 break;
32 }
33 case PENDING: {
34 this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
35 this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
36 }
37 }
38 })
39 return promise2
40}

7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。

需要注意的是,如果 promise1 的 onRejected 执行成功了,promise2 应该被 resolve

这里咱们其实已经在参数检查的时候做过了, 也就是这段代码

1const realOnFulfilled = this.isFunction(onFulfilled)
2 ? onFulfilled
3 : (value) => {
4 return value;
5 };
6const realOnRejected = this.isFunction(onRejected)
7 ? onRejected
8 : (reason) => {
9 throw reason;
10 };

7.4 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行 resolvePromise 方法

1then(onFulfilled, onRejected) {
2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
3 return value
4 }
5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
6 throw reason;
7 };
8 const promise2 = new MPromise((resolve, reject) => {
9 const fulfilledMicrotask = () => {
10 try {
11 const x = realOnFulfilled(this.value);
12 this.resolvePromise(promise2, x, resolve, reject);
13 } catch (e) {
14 reject(e)
15 }
16 };
17 const rejectedMicrotask = () => {
18 try {
19 const x = realOnRejected(this.reason);
20 this.resolvePromise(promise2, x, resolve, reject);
21 } catch (e) {
22 reject(e);
23 }
24 }
25
26 switch (this.status) {
27 case FULFILLED: {
28 fulfilledMicrotask()
29 break;
30 }
31 case REJECTED: {
32 rejectedMicrotask()
33 break;
34 }
35 case PENDING: {
36 this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
37 this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
38 }
39 }
40 })
41 return promise2
42}

8. resolvePromise

1resolvePromise(promise2, x, resolve, reject) {
2 // 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
3 // 这是为了防止死循环
4 if (promise2 === x) {
5 return reject(new TypeError('The promise and the return value are the same'));
6 }
7
8 if (x instanceof MPromise) {
9 // 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
10 // 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
11 queueMicrotask(() => {
12 x.then((y) => {
13 this.resolvePromise(promise2, y, resolve, reject);
14 }, reject);
15 })
16 } else if (typeof x === 'object' || this.isFunction(x)) {
17 // 如果 x 为对象或者函数
18 if (x === null) {
19 // null也会被判断为对象
20 return resolve(x);
21 }
22
23 let then = null;
24
25 try {
26 // 把 x.then 赋值给 then
27 then = x.then;
28 } catch (error) {
29 // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
30 return reject(error);
31 }
32
33 // 如果 then 是函数
34 if (this.isFunction(then)) {
35 let called = false;
36 // 将 x 作为函数的作用域 this 调用
37 // 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
38 try {
39 then.call(
40 x,
41 // 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
42 (y) => {
43 // 需要有一个变量called来保证只调用一次.
44 if (called) return;
45 called = true;
46 this.resolvePromise(promise2, y, resolve, reject);
47 },
48 // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
49 (r) => {
50 if (called) return;
51 called = true;
52 reject(r);
53 });
54 } catch (error) {
55 // 如果调用 then 方法抛出了异常 e:
56 if (called) return;
57
58 // 否则以 e 为据因拒绝 promise
59 reject(error);
60 }
61 } else {
62 // 如果 then 不是函数,以 x 为参数执行 promise
63 resolve(x);
64 }
65 } else {
66 // 如果 x 不为对象或者函数,以 x 为参数执行 promise
67 resolve(x);
68 }
69}

9. onFulfilled 和 onRejected 是微任务

咱们可以用 queueMicrotask 包裹执行函数

1const fulfilledMicrotask = () => {
2 queueMicrotask(() => {
3 try {
4 const x = realOnFulfilled(this.value);
5 this.resolvePromise(promise2, x, resolve, reject);
6 } catch (e) {
7 reject(e);
8 }
9 });
10};
11const rejectedMicrotask = () => {
12 queueMicrotask(() => {
13 try {
14 const x = realOnRejected(this.reason);
15 this.resolvePromise(promise2, x, resolve, reject);
16 } catch (e) {
17 reject(e);
18 }
19 });
20};

10. 简单写点代码测试一下

1const test = new MPromise((resolve, reject) => {
2 setTimeout(() => {
3 resolve(111);
4 }, 1000);
5}).then(console.log);
6
7console.log(test);
8
9setTimeout(() => {
10 console.log(test);
11}, 2000);

11. catch 方法

1catch (onRejected) {
2 return this.then(null, onRejected);
3}

12. promise.resolve

将现有对象转为 Promise 对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为 fulfilled。 注意这是一个静态方法, 因为咱们是通过 Promise.resolve 调用的, 而不是通过实例去调用的.

1static resolve(value) {
2 if (value instanceof MPromise) {
3 return value;
4 }
5
6 return new MPromise((resolve) => {
7 resolve(value);
8 });
9}

13. promise.reject

返回一个新的 Promise 实例,该实例的状态为 rejected。Promise.reject 方法的参数 reason,会被传递给实例的回调函数。

1static reject(reason) {
2 return new MPromise((resolve, reject) => {
3 reject(reason);
4 });
5}

14. promise.race

const p = Promise.race([p1, p2, p3]);

该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。 只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。

1static race(promiseList) {
2 return new MPromise((resolve, reject) => {
3 const length = promiseList.length;
4
5 if (length === 0) {
6 return resolve();
7 } else {
8 for (let i = 0; i < length; i++) {
9 MPromise.resolve(promiseList[i]).then(
10 (value) => {
11 return resolve(value);
12 },
13 (reason) => {
14 return reject(reason);
15 });
16 }
17 }
18 });
19
20}

写段测试代码

1const test = new MPromise((resolve, reject) => {
2 setTimeout(() => {
3 resolve(111);
4 }, 1000);
5});
6
7const test2 = new MPromise((resolve, reject) => {
8 setTimeout(() => {
9 resolve(222);
10 }, 2000);
11});
12
13const test3 = new MPromise((resolve, reject) => {
14 setTimeout(() => {
15 resolve(333);
16 }, 3000);
17});
18
19MPromise.race([test, test2, test3]).then(console.log);

all

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 如果所有Promise都成功,则返回成功结果数组
  • 如果有一个Promise失败,则返回这个失败结果
1static all(promises) {
2 const result = []
3 let count = 0
4 return new MyPromise((resolve, reject) => {
5 const addData = (index, value) => {
6 result[index] = value
7 count++
8 if (count === promises.length) resolve(result)
9 }
10 promises.forEach((promise, index) => {
11 if (promise instanceof MyPromise) {
12 promise.then(res => {
13 addData(index, res)
14 }, err => reject(err))
15 } else {
16 addData(index, promise)
17 }
18 })
19 })
20}

race

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 哪个Promise最快得到结果,就返回那个结果,无论成功失败
1static race(promises) {
2 return new MyPromise((resolve, reject) => {
3 promises.forEach(promise => {
4 if (promise instanceof MyPromise) {
5 promise.then(res => {
6 resolve(res)
7 }, err => {
8 reject(err)
9 })
10 } else {
11 resolve(promise)
12 }
13 })
14 })
15}

allSettled

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 把每一个Promise的结果,集合成数组,返回
1static allSettled(promises) {
2 return new Promise((resolve, reject) => {
3 const res = []
4 let count = 0
5 const addData = (status, value, i) => {
6 res[i] = {
7 status,
8 value
9 }
10 count++
11 if (count === promises.length) {
12 resolve(res)
13 }
14 }
15 promises.forEach((promise, i) => {
16 if (promise instanceof MyPromise) {
17 promise.then(res => {
18 addData('fulfilled', res, i)
19 }, err => {
20 addData('rejected', err, i)
21 })
22 } else {
23 addData('fulfilled', promise, i)
24 }
25 })
26 })
27}

any

any与all相反

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 如果有一个Promise成功,则返回这个成功结果
  • 如果所有Promise都失败,则报错
1static any(promises) {
2 return new Promise((resolve, reject) => {
3 let count = 0
4 promises.forEach((promise) => {
5 promise.then(val => {
6 resolve(val)
7 }, err => {
8 count++
9 if (count === promises.length) {
10 reject(new AggregateError('All promises were rejected'))
11 }
12 })
13 })
14 })
15 }
16}

More articles from Favori 重剑

debug和内存泄露

nodejs的debug方法

April 8th, 2020 · 1 min read

Javascript prototype 原型链

js-prototype

September 7th, 2019 · 1 min read
© 2016–2023 Favori 重剑
Link to $https://github.com/yuanguandongLink to $https://favori.zcool.com.cn/Link to $https://codepen.io/favori