介绍

p-map的功能是用来对一组Promise对象进行操作,当其中任何一个Promise的状态变为fulfilled时,执行我们传递的回调函数,只要有一个Promise状态变为rejected,所有未执行的Promise都不再执行。

项目地址:https://github.com/sindresorhus/p-map

源码分析

p-map的代码并不复杂,以下是p-map的核心代码:

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
const next = () => {
// 如果当前Promise状态为rejected,就不再执行下一个
if (isRejected) {
return;
}

const nextItem = iterator.next();
const i = currentIndex;
currentIndex++;

if (nextItem.done) {
isIterableDone = true;
// 如果全部执行成功,则resolve
if (resolvingCount === 0) {
resolve(ret);
}

return;
}

resolvingCount++;

Promise.resolve(nextItem.value)
// 对结果进行处理
.then(element => mapper(element, i))
.then(
value => {
ret[i] = value;
resolvingCount--;
next();
},
error => {
isRejected = true;
reject(error);
}
);
};

以上逻辑比较清晰,其中最大的亮点就是使用迭代器判断是否结束。大部分人遇到p-map这种需求,都会想到用Promise.allArray.prototype.map之类的方法去实现效果。例如:

1
2
3
4
5
function pMap(promises, mapper) {
return Promise.all(promises.map((item, i) => {
return Promise.resolve(item).then(data => mapper(data, i))
}))
}

这段代码和p-map库的实现差别在于:即使有一个Promise变为rejected,后面的Promise仍然会执行,所以实际上并不能满足需求。

p-map中迭代器的使用不仅大大简化了实现难度,还提供了额外的控制机会,concurrency选项能发挥作用,也是使用迭代器带来的好处。