使用 bluebird 实现更强大的 Promise(3)处理集合
- UID
- 1066743
|
使用 bluebird 实现更强大的 Promise(3)处理集合
处理集合之前的代码示例都针对单个 Promise。在实际中,经常会需要与多个 Promise 进行交互。比如,读取单个文件的操作返回的是 Promise 对象,而我们需要等待若干个文件的读取操作都成功之后,再执行其他操作。Promise.all 可以接受一个 Iterable 参数,并返回一个新的 Promise。结果的 Promise 只有在 Iterable 中包含的全部 Promise 对象都满足时,才会满足;任何 Promise 出现错误会导致结果 Promise 被拒绝。新的 Promise 的最终结果是一个包含 Iterable 中 Promise 的结果的数组。该 Iterable 中可以包含任何值。如果值不是 Promise,则其值会直接出现在结果中,并不需要等待 Promise 完成。在代码清单8中,我们使用 Promise.all 来等待3个读取文件操作完成。
清单8. Promise.all 使用示例1
2
3
4
5
| Promise.all([
fs.readFileAsync(path.join(__dirname, '1.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '2.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '3.txt'), 'utf-8')
]).then(results => console.log(results.join(', '))).catch(console.error);
|
在很多情况下的做法都需要把 Iterable 中的对象转换成 Promise 之后,再等待这些 Promise 完成。对于这样的场景,可以使用 Promise.map。map 方法的第一个参数是 Iterable 对象,第二个参数是转换为 Promise 的方法,第三个参数是可选的配置对象,可以使用属性 concurrency 来控制同时运行的 Promise 的数量。在代码清单9代码清单9中,我们使用 Promise.map 把包含文件名称的数组转换成读取文件内容的 Promise 对象,再等待读取操作完成。的功能与代码清单8一样,但是实现更简单。
清单9. Promise.map 的使用示例1
2
3
| Promise.map(['1.txt', '2.txt', '3.txt'],
name => fs.readFileAsync(path.join(__dirname, name), 'utf-8')
).then(results => console.log(results.join(', '))).catch(console.error);
|
Promise.mapSeries 的作用与 Promise.map 相同,只不过 mapSeries 按照 Iterable 中的顺序依次遍历每个元素。
在有多个 Promise 时,如果只需要等待其中部分 Promise 完成,可以使用 Promise.some 并指定完成的 Promise 数量。在代码清单10中,只需要等待2个文件读取操作完成即可。
清单10. Promise.some 的使用示例1
2
3
4
5
| Promise.some([
fs.readFileAsync(path.join(__dirname, '1.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '2.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '3.txt'), 'utf-8')
], 2).then(results => console.log(results.join(', '))).catch(console.error);
|
Promise.any 相当于使用 Promise.some 并把数量设为1,不过 Promise.any 的结果不是一个长度为1的数组,还是具体的单个值。Promise.race 的作用类似 any,不过 race 的结果有可能是被拒绝的 Promise。因此推荐的做法是使用 any。
Promise.filter 可以等待多个 Promise 的完成,并对结果进行过滤。它实际上的效果相当于在 Promise.map 之后使用 Array 的 filter 方法来进行过滤。在代码清单11中,Promise.filter 用来过滤掉内容长度不大于1的文件。
清单11. Promise.filter 的使用示例1
2
3
4
5
| Promise.filter([
fs.readFileAsync(path.join(__dirname, '1.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '2.txt'), 'utf-8'),
fs.readFileAsync(path.join(__dirname, '3.txt'), 'utf-8')
], value => value.length > 1).then(results => console.log(results.join(', '))).catch(console.error);
|
Promise.each 对 Iterable 中的元素进行依次处理。处理方法也可以返回 Promise 对象来表示异步处理。只有对上一个元素的处理完成之后,才会处理下一个元素。
Promise.reduce 把多个 Promise 的结果缩减成单个值。其作用类似 Array 的 reduce 方法,但是可以处理 Promise 对象。在代码清单12中,第一个参数是待处理的文件名称数组;第二个参数是进行累积操作的方法,total 表示当前累积值,用来与读取到的当前文件的长度相加;第三个参数是累积的初始值。从代码中可以看到,累积操作也可以返回 Promise 对象。Promise.reduce 会等待 Promise 完成。
清单12. Promise.reduce 的使用示例1
2
3
4
5
| Promise.reduce(['1.txt', '2.txt', '3.txt'],
(total, name) => {
return fs.readFileAsync(path.join(__dirname, name), 'utf-8').then(data => total + data.length);
}
, 0).then(result => console.log(`Total size: ${result}`)).catch(console.error);
|
Promise.all 用来处理动态数量的 Promise,Promise.join 用来处理固定数量的不相关的 Promise。
Promise.method 用来封装一个方法,使其返回 Promise。Promise.try 用来封装可能产生问题的方法调用,并根据调用结果来决定 Promise 的状态。 |
|
|
|
|
|