等待的承诺仍在返回 <pending>
awaited Promises still returning <pending>
我有一组关于人的数据对象。每个人对象包含 0-n 个附加信息的 URL(此人的客人)。
我想处理此列表,调用每个 'guest' URL 并将客人的姓名包含在原始数据集中。
上下文:这是一个 AWS lambda 函数。我在本地使用 lambda-local 到 运行。 (lambda-local -l index.js -e fixtures/test_event1.json
).
我已成功使用 await/async 检索初始数据集。
但是如果正在处理这些关于客人信息的进一步电话,我无法接听。它总是显示一个挂起的 Promise,即使等待结果。
// index.js
const fetch = require('node-fetch');
exports.handler = async function(event){
try {
let registrations = await getEventRegistrations();
console.log(registrations);
/* All good here - sample console output
[ { contactId: 43452967,
displayName: 'aaa, bbb',
numGuests: 0,
guestUrls: [] },
{ contactId: 43766365,
displayName: 'bbb, ccc',
numGuests: 1,
guestUrls:
[ 'https://<URL>' ] },
{ contactId: 43766359,
displayName: 'ccc, ddd',
numGuests: 2,
guestUrls:
[ 'https://<URL>',
'https://<URL> ] } ]
*/
// Expanding the guest URLs is proving problematic - see expandGuests function below
registrations = registrations.map(expandGuests);
console.log(registrations);
/* Registrations are just pending Promises here, not the real data
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
*/
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(registrations),
};
}
catch (exception) {
console.log(exception);
return {
statusCode: 500,
body: 'Unable to retrieve data.'
};
}
};
function getEventRegistrations() {
return fetch('<URL>')
.then(res => res.json())
.catch(function (error) {
console.log('Event registrants request failed', error);
return null;
});
}
function getGuestName(url) {
return fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
async function expandGuests(data) {
const promises = data.guestUrls.map(url => getGuestName(url));
data.guestNames = await Promise.all(promises);
return data;
}
我如何解决这些未决的 Promise 以及 return 有用的数据?
谢谢。
array.map 不包含任何等待承诺的逻辑。它只是为数组的每个元素调用函数,然后同步生成一个结果数组。如果你传入异步函数,那么结果是一个承诺数组(因为所有异步函数 return 承诺)。
您需要使用 Promise.all
创建一个承诺,该承诺将在所有单个承诺都解决后解决,然后 await
那。
const promises = data.guestUrls.map(url => getGuestName(url));
data.guestNames = await Promise.all(promises);
P.S,我强烈建议不要将 async/await 与 .then 混合使用。实际需要这样做的情况非常少见,所以大多数时候你只是让代码更难理解。例如这个函数:
async function getGuestName(url) {
return await fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
应该这样做:
async function getGuestName(url) {
try {
const res = await fetch(url);
const guest = await res.json();
return guest.DisplayName;
} catch (error) {
console.log('Guest name request failed', error);
return null;
}
}
或者像这样
function getGuestName(url) {
return fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
评论指出映射 async
函数将 return Promise 数组是正确的。他们没有明确提到的是你有两张地图,哪一张有问题。
问题在行中:
reservations = reservations.map(expandGuests);
任何时候你使用地图,你都需要真正解决return的承诺。
所以:
const mappedPromises = reservations.map(expandGuests); //returns an Array of Pending promises
const mappedReservations = await Promise.all(mappedPromises); //resolves the promises
我有一组关于人的数据对象。每个人对象包含 0-n 个附加信息的 URL(此人的客人)。
我想处理此列表,调用每个 'guest' URL 并将客人的姓名包含在原始数据集中。
上下文:这是一个 AWS lambda 函数。我在本地使用 lambda-local 到 运行。 (lambda-local -l index.js -e fixtures/test_event1.json
).
我已成功使用 await/async 检索初始数据集。
但是如果正在处理这些关于客人信息的进一步电话,我无法接听。它总是显示一个挂起的 Promise,即使等待结果。
// index.js
const fetch = require('node-fetch');
exports.handler = async function(event){
try {
let registrations = await getEventRegistrations();
console.log(registrations);
/* All good here - sample console output
[ { contactId: 43452967,
displayName: 'aaa, bbb',
numGuests: 0,
guestUrls: [] },
{ contactId: 43766365,
displayName: 'bbb, ccc',
numGuests: 1,
guestUrls:
[ 'https://<URL>' ] },
{ contactId: 43766359,
displayName: 'ccc, ddd',
numGuests: 2,
guestUrls:
[ 'https://<URL>',
'https://<URL> ] } ]
*/
// Expanding the guest URLs is proving problematic - see expandGuests function below
registrations = registrations.map(expandGuests);
console.log(registrations);
/* Registrations are just pending Promises here, not the real data
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
*/
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(registrations),
};
}
catch (exception) {
console.log(exception);
return {
statusCode: 500,
body: 'Unable to retrieve data.'
};
}
};
function getEventRegistrations() {
return fetch('<URL>')
.then(res => res.json())
.catch(function (error) {
console.log('Event registrants request failed', error);
return null;
});
}
function getGuestName(url) {
return fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
async function expandGuests(data) {
const promises = data.guestUrls.map(url => getGuestName(url));
data.guestNames = await Promise.all(promises);
return data;
}
我如何解决这些未决的 Promise 以及 return 有用的数据?
谢谢。
array.map 不包含任何等待承诺的逻辑。它只是为数组的每个元素调用函数,然后同步生成一个结果数组。如果你传入异步函数,那么结果是一个承诺数组(因为所有异步函数 return 承诺)。
您需要使用 Promise.all
创建一个承诺,该承诺将在所有单个承诺都解决后解决,然后 await
那。
const promises = data.guestUrls.map(url => getGuestName(url));
data.guestNames = await Promise.all(promises);
P.S,我强烈建议不要将 async/await 与 .then 混合使用。实际需要这样做的情况非常少见,所以大多数时候你只是让代码更难理解。例如这个函数:
async function getGuestName(url) {
return await fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
应该这样做:
async function getGuestName(url) {
try {
const res = await fetch(url);
const guest = await res.json();
return guest.DisplayName;
} catch (error) {
console.log('Guest name request failed', error);
return null;
}
}
或者像这样
function getGuestName(url) {
return fetch(url)
.then(res => res.json())
.then(guest => guest.DisplayName)
.catch(function (error) {
console.log('Guest name request failed', error);
return null;
});
}
评论指出映射 async
函数将 return Promise 数组是正确的。他们没有明确提到的是你有两张地图,哪一张有问题。
问题在行中:
reservations = reservations.map(expandGuests);
任何时候你使用地图,你都需要真正解决return的承诺。
所以:
const mappedPromises = reservations.map(expandGuests); //returns an Array of Pending promises
const mappedReservations = await Promise.all(mappedPromises); //resolves the promises