извлечение каждого элемента внутри массива

#javascript #angular #promise #fetch #promise.all

#javascript #угловой #обещание #выборка #promise.all

Вопрос:

Так что я почти уверен, что это как-то связано с Promise.all или что-то в этом роде, но я не уверен, как это сделать. буду признателен, если кто-нибудь сможет помочь мне с этим кодом.

Примечание: массив, который я пытаюсь сопоставить, представляет собой массив объектов, если это имеет значение

 const productsArray = this.cartProducts.map(product => 
      fetch(`/api/products/getDetails/${product.clientId}`))
      .then(res => res.json())
      .then(data => {
        console.log(data)
      })
 

Я не могу даже запустить этот код, но я не уверен, что именно я должен делать…

Это моя ошибка из Visual Studio code.

 property 'then' does not exist on type 'promise<response>[]'
 

Ответ №1:

fetch() результат — promise, поэтому вам нужно использовать Promise.all()

 const promises = await Promise.all(this.cartProducts.map(product => fetch(`/api/products/getDetails/${product.clientId}`))
const productsArray = await Promise.all(promises.map(p => p.json()))
 

Комментарии:

1. спасибо, это было именно то, что я искал! это отлично работает, однако я получаю ошибку 400 stauts, прежде чем она заработает… не уверен, почему

Ответ №2:

Ответ Уильяма Вана совершенно хорош, но вы можете захотеть использовать async / await, чтобы это понравилось:

 const productsArray = this.cartProducts.map(async product => {
      const res = await fetch(`/api/products/getDetails/${product.clientId}`);
      const data = res.json();
      return data;
});
 

Это может быть упрощено с помощью:

 const productsArray = this.cartProducts.map(async product => {
      return await fetch(`/api/products/getDetails/${product.clientId}`).json();
});
 

Однако имейте в виду, что такой шаблон будет более «синхронным», чем использование шаблона Promise.all, поскольку каждый продукт будет извлекаться только после получения предыдущего. Обещание.все будут извлекать весь продукт параллельно.

Комментарии:

1. асинхронное ожидание внутри map() работает не так, как ожидалось.

2. Можете ли вы уточнить? Это мой фрагмент? Или вообще? Я использовал этот шаблон несколько раз, и он работал до конца, насколько я помню.

Ответ №3:

TL; DR: сопоставьте каждый элемент в массиве с вызовом выборки и оберните их вокруг Promise.all() .

 Promise.all(
  this.cartProducts.map(p =>
    fetch(`/api/products/getDetails/${p.clientId}`).then(res => res.json())
  )
).then(products => console.log(products));
 

Объяснение

fetch() возвращает Promise a.k.a «Я обещаю, что дам вам значение в будущем». Когда приходит время, это будущее значение разрешается и передается обратному .then(callback) вызову для дальнейшей обработки. Результатом .then() также является a Promise , что означает, что они объединяются в цепочку.

 // returns Promise
fetch('...')
// also returns Promise
fetch('...').then(res => res.json())
// also returns Promise where the next resolved value is undefined
fetch('...').then(res => res.json()).then(() => undefined)
 

Таким образом, приведенный ниже код вернет другой Promise , где разрешенное значение является проанализированным объектом Javascript.

   fetch('...').then(res => res.json())
 

Array.map() сопоставляет каждый элемент с результатом обратного вызова и возвращает новый массив после выполнения всех обратных вызовов, в данном случае массив Promise .

 const promises = this.cartProducts.map(p =>
  fetch("...").then(res => res.json())
);
 

После вызова map у вас будет список Promise ожидающих разрешения. Они не содержат фактическое значение продукта, полученное с сервера, как описано выше. Но вам не нужны обещания, вы хотите получить массив окончательных разрешенных значений.

Вот где Promise.all() вступает в игру. Они являются версией обещания Array.map() , где они «сопоставляют» каждый Promise с разрешенным значением с помощью Promise API.

Из-за этого Promise.all() разрешится еще одно новое Promise после того, как все отдельные обещания в promises массиве будут разрешены.

 // assuming the resolved value is Product

// promises is Promise[]
const promises = this.cartProducts.map(p =>
  fetch("...").then(res => res.json())
);

Promise.all(promises).then(products => {
  // products is Product[]. The actual value we need
  console.log(products)
})