Promise

Promise

是什么

Promise 是 JS 中进行异步编程的新解决方案(旧方案是单纯使用回调函数)

从语法上来说: Promise 是一个构造函数

从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值

状态

pending

resolved/fulfilled

rejected

无论变为成功还是失败, 都会有一个结果数据

成功的结果数据一般称为 value, 失败的结果数据一般称为 reason

流程

优势

  1. 指定回调函数更加灵活,原先需要在异步任务前指定。如今异步任务在new时写入,成功/失败回调在then中绑定

  2. 支持链式调用,解决回调地狱问题

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1.创建一个Promise实例
//2.Promise构造函数接收一个函数作为参数,函数的两个参数分别是resolve和reject。它们均是函数
const promise=new Promise(function(resolve,reject){
if(操作是否成功){
resolve(value)
//3.当异步操作成功时,调用resolve()。状态发生改变(pending->fulfilled),并将结果作为参数传递出去
}else{
reject(error)
//4.当异步操作失败是,调用reject()。状态发生改变(pending->rejected),并将错误作为参数传递出去
}
})
//5.可以使用then方法指定resolved状态和rejected状态的回调函数.then方法接收两个回调函数作为参数(这俩个函数都是可选的)
promise.then(function(value){
//6.状态变为resolved(在这里统一只指`fulfilled`状态)时调用,可使用传出的value
},function(error){
// 7.状态变为rejected时调用,可使用传出的error
})

实现一个简易的Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 使用
const a = new Promise((resolve, rejct) => {
if ('成功') {
resolve(value)
} else {
reject(error)
}
})
a.then((value) => {
console.log(value)
}, (error) => {
throw new Error(error)
})

// 实现
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.resolveCallbacks = []
this.rejectCallbacks = []

const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.resolveCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.rejectCallbacks.forEach(fn => fn())
}
}

try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}

then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if (this.status === PENDING) {
this.resolveCallbacks.push(() => {
onFulfilled(this.value)
})
this.rejectCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}

手写API

静态方法

Promise.all(iterable)

这个方法返回一个新的 promise 对象,等到所有的 promise 对象都成功或有任意一个 promise 失败。

如果所有的 promise 都成功了,它会把一个包含 iterable 里所有 promise 返回值的数组作为成功回调的返回值。顺序跟 iterable 的顺序保持一致。

一旦有任意一个 iterable 里面的 promise 对象失败则立即以该 promise 对象失败的理由来拒绝这个新的 promise。

Promise.allSettled(iterable)

等到所有 promise 都已敲定(每个 promise 都已兑现或已拒绝)。

返回一个 promise,该 promise 在所有 promise 都敲定后完成,并兑现一个对象数组,其中的对象对应每个 promise 的结果。

Promise.any(iterable)

接收一个 promise 对象的集合,当其中的任意一个 promise 成功,就返回那个成功的 promise 的值。

Promise.race(iterable)

等到任意一个 promise 的状态变为已敲定。

当 iterable 参数里的任意一个子 promise 成功或失败后,父 promise 马上也会用子 promise 的成功返回值或失败详情作为参数调用父 promise 绑定的相应处理函数,并返回该 promise 对象。

Promise.reject(reason)

返回一个状态为已拒绝的 Promise 对象,并将给定的失败信息传递给对应的处理函数。

Promise.resolve(value)

返回一个状态由给定 value 决定的 Promise 对象。如果该值是 thenable(即,带有 then 方法的对象),返回的Promise 对象的最终状态由 then 方法执行结果决定;否则,返回的 Promise 对象状态为已兑现,并且将该 value 传递给对应的 then 方法。

通常而言,如果你不知道一个值是否是 promise 对象,使用 Promise.resolve(value) 来返回一个 Promise 对象,这样就能将该 value 以 promise 对象形式使用。

实例方法

Promise.prototype.catch()

为 promise 添加一个被拒绝状态的回调函数,并返回一个新的 promise,若回调函数被调用,则兑现其返回值,否则兑现原来的 promise 兑现的值。

Promise.prototype.then()

为 promise 添加被兑现和被拒绝状态的回调函数,其以回调函数的返回值兑现 promise。若不处理已兑现或者已拒绝状态(例如,onFulfilledonRejected 不是一个函数),则返回 promise 被敲定时的值。

Promise.prototype.finally()

为 promise 添加一个回调函数,并返回一个新的 promise。这个新的 promise 将在原 promise 被兑现时兑现。而传入的回调函数将在原 promise 被敲定(无论被兑现还是被拒绝)时被调用。

Promise.all

  1. Promise.all()接受一个promise的iterable类型
  2. 只有数组中全部的 Promise 都变为 resolve 的时候,返回一个成果结果的数组(按参数内的promise顺序排列,而不是promise完成的顺序)
  3. 只要有一个失败,状态就变成 rejected,将失败的那个结果给失败状态的回调函数
  4. 数组为空时会返回[]

使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
// 全部resolve, 输出数组
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
}, (error) => {
throw new Error(error)
});
// expected output: Array [3, 42, "foo"]

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Promise.all = (promises) => {
// 可迭代对象转数组
let promises = Array.from(promises)
return new Promise((resolve, reject) => {
const n = promises.length
// 数组为空的情况
if (n === 0) resolve([])
else {
let results = [] // 结果数组
let index = 0 // 记录多少个 promise 已完成
let processData = (value, i) => {
results[i] = value
if (++index === n) resolve(results)
}
for (let i = 0; i < n; i++) {
const curPromise = promises[i]
// 判断是否为 promise, 其实这样判断是不够的
if (curPromise instanceof Promise) {
curPromise.then(
data => processData(data, i),
err => reject(err)
)
} else {
processData(curPromise, i)
}
}
}
})
}

Promise.race

Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。

数组为空时什么都不会返回

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
promise.prototype.race = (promiseArray) => {
promiseArray = Array.from(promiseArray)
return new Promise((resolve, reject) => {
const n = promiseArray.length
for (let i = 0; i < n; i++) {
const curPromise = promiseArray[i]
if (curPromise instanceof Promise) {
curPromise.then(
(value) => resolve(value),
(error) => reject(error)
)
} else {
resolve(curPromise)
}
}
})
}

Promise.allSettled

Promise.allSettled() 可用于并行执行独立的异步操作,并收集这些操作的结果。

该函数接受一个 promise 数组(通常是一个可迭代对象)作为参数:

1
const statusesPromise = Promise.allSettled(promises);

当所有的输入 promises 都被 fulfilledrejected 时,statusesPromise 会解析为一个具有它们状态的数组

  1. { status: 'fulfilled', value: value } — 如果对应的 promise 已经 fulfilled
  2. 或者 {status: 'rejected', reason: reason} 如果相应的 promise 已经被 rejected

使用

1
2
3
4
5
6
7
8
9
10
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result.status)));

// expected output:
// "fulfilled"
// "rejected"

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
promise.promise.allSettled = (promiseArray) => {
promiseArray = Array.from(promiseArray)
return new Promise((resolve, reject) => {
const n = promiseArray.length
const results = []
for (let i = 0; i < n; i++) {
const curPromise = promiseArray[i]
let index = 0
const addData = (status, d, i) => {
let tmpObj
if (status === 'fulfilled') {
tmpObj = {
status: status,
value: d
}
} else if (status === 'rejected') {
tmpObj = {
status: status,
reason: d,
}
}
results[i] = tmpObj
if (++index === n) resolve(res)
}
if (curPromise instanceof Promise) {
curPromise.then(
(value) => addData('fulfilled', value, i),
(reason) => addData('rejected', reason, i)
)
} else {
addData('fulfilled', curPromise, i)
}
}
})
}

Promise.any

  • 如果有一个Promise成功,则返回这个成功结果
  • 如果所有Promise都失败,则报错

使用

1
2
3
4
5
6
7
8
9
10
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Promise.prototype.any = (promiseArray) => {
promiseArray = Array.from(promiseArray)
return new Promise((resolve, reject) => {
const n = promiseArray.length
if (n === 0) reject([])
let count = 0
for (let i = 0; i < n; i++) {
const curPromise = promiseArray[i]
if (curPromise instanceof Promise) {
curPromise.then((value) => {
resolve(value)
}, (error) => {
count++
if (count === n) {
reject(new Error('All promises were rejected'))
}
})
} else {
resolve(curPromise)
}
}
})
}

Promise 控制并发数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
async function asyncPool(promiseArray, limit) {
promiseArray = Array.from(promiseArray)
const res = [] // 存放所有 promise 实例
const executing = [] // 存放目前正在执行的 promise
const n = promises.length
for (promise of promises) {
// promise如果不是Promise,那么就通过Promise.resolve将其包裹为promise,如果是Promise,返回的仍是原promise
const p = Promise.resolve(promise)
res.push(p)
if (limit < n) {
// 当这个promise状态变为fulfilled后,将其从正在执行的promise列表executing中删除
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
executing.push(e)
if (executing.length >= limit) {
// 一旦正在执行的promise列表数量等于限制数,就使用Promise.race等待某一个promise状态发生变更,
// 状态变更后,就会执行上面then的回调,将该promise从executing中删除,
// 然后再进入到下一次for循环,生成新的promise进行补充
await Promise.race(executing)
}
}
}
return Promise.all(res)
}

(async () => {
const res = await asyncPool([promise1, promise2, promise3, promise4], 2);
console.log(res);
})();

Promise
http://example.com/2022/06/10/Promise/
Author
John Doe
Posted on
June 10, 2022
Licensed under