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