减少数组链接承诺

此设计模式对于从元素列表生成一系列异步操作非常有用。

有两种变体:

  • 然后减少,只要连锁经历成功,就会建立一个持续的链条。
  • 捕获减少,只要链条出现错误,就会建立一个持续的链条。

****然后减少

这种模式的变体构建了一个 .then() 链,可能用于链接动画或制作一系列依赖的 HTTP 请求。

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

说明:

  1. 我们在源数组上调用 .reduce() ,并提供 Promise.resolve() 作为初始值。
  2. 减少的每个元素都会将 .then() 添加到初始值。
  3. reduce() 的产品将是 Promise.resolve()。然后(…)。然后(…)。
  4. 我们在 reduce 之后手动附加 .then(successHandler, errorHandler) ,以便在前面的所有步骤都已解决后执行 successHandler。如果任何步骤失败,则 errorHandler 将执行。

注意:then 减少是 Promise.all() 的顺序对应。

****捕获减少

这种模式的变体构建了一个 .catch() 链,可用于为一些镜像资源顺序探测一组 Web 服务器,直到找到工作服务器。

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

说明:

  1. 我们在源阵列上调用 .reduce() ,并提供 Promise.reject() 作为初始值。
  2. 每个元素减少将一个添加 .catch() 到初始值。
  3. reduce() 的产品将是 Promise.reject().catch(…).catch(...)
  4. 我们在 reduce 之后手动附加 .then(successHandler, errorHandler) ,以便在前面的任何步骤解决后执行 successHandler。如果所有步骤都失败了,那么 errorHandler 将会执行。

注意:catch 减少是 Promise.any() 的顺序对应(在 bluebird.js 中实现,但目前不在本机 ECMAScript 中)。