代码之家  ›  专栏  ›  技术社区  ›  Alexander Solonik

一系列承诺是如何与reduce一起工作的?

  •  6
  • Alexander Solonik  · 技术社区  · 7 年前

    HERE

    const tasks = getTaskArray();
    return tasks.reduce((promiseChain, currentTask) => {
        return promiseChain.then(chainResults =>
            currentTask.then(currentResult =>
                [ ...chainResults, currentResult ]
            )
        );
    }, Promise.resolve([])).then(arrayOfResults => {
        // Do something with all results
    });
    

    因此,在不改变大部分代码的情况下,我制作了以下演示:

    const tasks = [ fetch('https://jsonplaceholder.typicode.com/todos/1') , 
                    fetch('https://jsonplaceholder.typicode.com/todos/2') ,   
                    fetch('https://jsonplaceholder.typicode.com/todos/3')  ];
    
    
    tasks.reduce((promiseChain, currentTask) => {
    
        console.log(promiseChain);  
    
        return promiseChain.then(chainResults => {
            return currentTask.then(currentResult =>
                [ ...chainResults, currentResult ]
            )
        });
    }, Promise.resolve([])).then(arrayOfResults => {
        // Do something with all results
        console.log(arrayOfResults);
    });
    

    但我仍然不明白,因为reduce简单地只是一个forEach循环,而在reduce内部我们依赖于返回的承诺,有什么保证reduce函数不会在不触发then()的情况下循环通过数组中的所有元素(在本例中是一个承诺数组)?

    1 回复  |  直到 7 年前
        1
  •  1
  •   D Lowther    7 年前

    好的,从阅读这篇文章回来,给出一个更完整的答案。这种策略适用于相互依赖但并不总是相同的异步任务。如果它们是一个固定结构,您可以(从示例中)执行以下操作:

    return task1.then(result1 =>
        task2.then(result2 =>
            task3.then(result3 =>
                [ result1, result2, result3 ]
            )
        )
    ).then(arrayOfResults => {
        // Do something with all results
    });
    

    return dbOrm.task1.create()
      .then(newRecord =>
        // task 2 requires the id from the new record to operate
        dbOrm.task2.create({task1_id: newRecord.id})
          .then(result2 =>
            // some other async that relies on result2
            task3(result2).then(result3 =>
                [ result1, result2, result3 ]
            )
        )
    ).then(arrayOfResults => {
        // Do something with all results
    });
    

    这是一组固定的依赖项,它们相互依赖以进行操作,您需要所有依赖项的结果才能继续。

    您链接的示例是针对这种串行执行的,但是在具有非固定依赖关系的情况下。Reduce用于同步构建异步操作链,然后这些异步操作可以自行解析,并且由于Reduce函数返回已解析的承诺,因此您可以将另一个函数从其末端链接起来,以处理完成的链。

    Reduce不仅仅是一个forEach循环,即使它们都使用迭代来移动数组。Reduce还将上一次迭代的返回结果传递给下一次迭代。您正在将您的任务组“减少”为一个已完成的任务;forEach不改变它所操作的数组(而Map,另一个迭代数组函数,从旧数组返回一个修改过的新数组)。

    因此,使用示例代码:

    const tasks = getTaskArray();
    return tasks.reduce((promiseChain, currentTask) => {
        return promiseChain.then(chainResults =>
            currentTask.then(currentResult =>
                [ ...chainResults, currentResult ]
            )
        );
    }, Promise.resolve([])).then(arrayOfResults => {
        // Do something with all results
    });
    

    // 1
    Promise.resolve([])
      .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])
    
    // 2
    Promise.resolve([])
      .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])
      .then(chainResults => task2().then(task2Result => ([ ...chainResults, task2Result])
    
    // the then after the reduce
    Promise.resolve([])
      .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])
      .then(chainResults => task2().then(task2Result => ([ ...chainResults, task2Result])
      .then(arrayOfResults => //do Something)
      .catch(//because you should handle errors)