Примените операцию к каждому результату в массиве, разрешенном Promise без вложенности - PullRequest
0 голосов
/ 14 октября 2018

ESlint и весь остальной мир говорят мне избегать вложенных Обещаний.Тем не менее, как можно применить функцию к нескольким элементам по отдельности, когда предыдущее обещание возвращает массив?Например, я хочу запустить doSomethingWithIt для каждого элемента, возвращенного предыдущим обещанием, а также сделать что-то с результатом этого.

function getSomeThings() {
   return new Promise((resolve, reject) => {
     resolve(['one', 'two', 'three'])
   })
}

function doSomethingWithIt(theThing) {
  return new Promise((resolve, reject) => {
     console.log(theThing)
     resolve("Did a thing")
  })
}

getSomeThings().then((things) => {
   things.forEach((thing) => {
      doSomethingWithIt(thing)
       .then((result) => {
          console.log(`Result was: ${result}`)
       })
   })
})

В действительности, вместо того, чтобы просто печатать возвращаемое значение, эта функция может возвращать идентификатор или что-то полезное для регистрации после завершения операции (например, фиксация в базе данных).

Как этого достичь, не вкладывая обещания?Нужно ли добавить шаг, который использует Promise.all для агрегирования результатов?Или есть более аккуратный способ сделать это ...

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

ESlint и весь остальной мир говорят мне избегать вложенных Обещаний.

Да, вам следует избегать этого , когда вы можете .Однако есть много ситуаций, когда вложение полностью уместно - и магия обещаний заключается в том, что они могут быть вложенными, в то же время производя тот же конечный результат.

Совет ESlin сродни "избегать отступов".Это правда, вы не должны писать вложенные блоки, когда они вам не нужны.Тем не менее, ваш вариант использования: « применить операцию к каждому результату », и для этого требуется цикл, который оправдывает вложение / отступ.

Конечно, вы должны избегать forEach и верните соответствующее обещание для всех завершенных операций цикла:

getSomeThings().then(things => {
  return Promise.all(things.map(thing => {
    return doSomethingWithIt(thing).then(result => {
      console.log(`Result for ${thing} was ${result}`);
    });
  }));
}).then(() => {
  console.log("Did all things");
});
0 голосов
/ 14 октября 2018

Вы бы использовали Promise.all для тех обещаний, которые вы создаете в цикле.Не только для того, чтобы сделать ESLint счастливым, но и для того, чтобы поддерживать полную цепочку успеха / неудач:

getSomeThings()
    .then((things) => Promise.all(things.map(doSomethingWithIt)))
    .then((results) => {
        for (const result of results) {
            console.log(`Result was: ${result}`);
        }
    })
    .catch((error) => {
        // Handle/report errors
    });

Live Пример:

function getSomeThings() {
   return new Promise((resolve, reject) => {
     resolve(['one', 'two', 'three'])
   })
}

function doSomethingWithIt(theThing) {
  return new Promise((resolve, reject) => {
     console.log(theThing)
     resolve("Did a thing")
  })
}

getSomeThings()
    .then((things) => Promise.all(things.map(doSomethingWithIt)))
    .then((results) => {
        for (const result of results) {
            console.log(`Result was: ${result}`);
        }
    })
    .catch((error) => {
        // Handle/report errors
    });

Да, это означает, что вы не получите console.log для любого из них, пока все эти doSomethingWith обещания не будут разрешены.Часто это хорошо.Но если это не так, то было бы разумно нарушить правило ESLint (которое, как сказал Берги в комментарий , универсально)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...