Как массив обещаний работает именно с Reduce? - PullRequest
0 голосов
/ 13 ноября 2018

Я читал эту статью ЗДЕСЬ , в которой рассказывается о том, как вы можете использовать сокращение с обещаниями, и в конце показан следующий фрагмент:

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 Ответ

0 голосов
/ 13 ноября 2018

Хорошо, вернемся к прочтению статьи с более полным ответом. Эта тактика предназначена для асинхронных задач, которые зависят друг от друга, но не всегда одинаковы. Если бы они были фиксированной структурой, вы бы сделали (из примера):

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
});

Вы бы получили что-то вроде этого, учитывая 2 итерации:

// 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...