javascript - 如何将异步函数映射到列表上?

标签 javascript es6-promise

显然,给定一个列表 l 和一个返回 Promise 的函数 f,我可以这样做:

Promise.all(l.map(f));

困难的部分是,我需要按顺序映射每个元素。也就是说,第一个元素的映射必须在下一个元素开始之前解析。我想防止任何并行性。

我知道如何做到这一点,我将作为答案给出,但我不确定这是一个好的答案。

编辑:有些人的印象是,由于 Javascript 本身是单线程的,因此 Javascript 中不可能并行。

考虑以下代码:

const delay = t => new Promise(resolve => setTimeout(resolve, t));
mapAsync([3000, 2000, 1000], delay).then(n => console.log('beep: ' + n));

mapAsync() 的简单实现会导致每秒打印一次“beep”,持续三秒 - 数字按升序排列 - 但正确 蜂鸣声的间隔时间会在六秒内逐渐增加,数字按降序排列。

举一个更实际的例子,想象一个调用 fetch() 并在包含数千个元素的数组上调用的函数。

进一步编辑:

有人不相信我,所以 here是 fiddle 。

最佳答案

const mapAsync = (l, f) => new Promise((resolve, reject) => {
  const results = [];
  const recur = () => {
    if (results.length < l.length) {
      f(l[results.length]).then(v => {
        results.push(v);
        recur();
      }).catch(reject);
    } else {
      resolve(results);
    }
  };
  recur();
});

编辑: Tholle 的评论让我发现了这个更加优雅且(我希望)anti-pattern -免费解决方案:

const mapAsync = (l, f) => {
  const recur = index =>
    index < l.length
      ? f(l[index]).then(car => recur(index + 1).then(cdr => [car].concat(cdr)))
      : Promise.resolve([]);

  return recur(0);
};

进一步编辑:

适当命名的 Try-catch-finally 建议使用 reduce 进行更简洁的实现。欢迎进一步改进。

const mapAsync2 = (l, f) =>
  l.reduce(
    (promise, item) =>
      promise.then(results => 
        f(item).then(result => results.concat([result]))),
    Promise.resolve([])
  );

关于javascript - 如何将异步函数映射到列表上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41908706/

相关文章:

php - php中如何返回错误回调?

javascript - React 路由器 activeClassName 没有为子路由设置事件类

javascript - 使用 javascript 中的 laravel 选项

javascript - 从深层对象获取属性值

javascript - 等待 Promise 内的异步函数

javascript - 为什么我的第二个 javascript promise 调用返回与第一个相同的值?

javascript - 这个选择器的功能

javascript - 如何使用映射渲染 Axios 函数的结果

javascript - 使用 async/await 和 try/catch 进行分层 api 调用

javascript - 在通过 setTimeout 或 promise 阻止代码之前更新 DOM