问题描述
我正在尝试从 API 获取数据,但结果一直未定义。我使用 promise.all 来链接 API 调用,然后链接 promise 以对数据执行其他操作。我似乎无法将我的结果传递给 state。
这是违规代码:
if (gameDifficulty === "mixed") {
const result = await Promise.all([
fetchClient.getData(
getEndpoint(
`amount=${countValues[0]}&difficulty=easy&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[1]}&difficulty=medium&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[2]}&difficulty=hard&type=${questionType}`
)
),])
.then(function (responses) {
console.log(responses);
console.log(result); //returns undefined
return Promise.all(
responses.map(function (response,idx) {
return fetchClient.processData(response,"results");
})
);
})
.then(function (data) {
console.log(data);
console.log(result); // returns undefined
return [...data[0],...data[1],...data[2]];
});
}
解决方法
在您的浏览器中转到您的网络选项卡发送一个 api 请求,看看它是否正在发送任何飞行前请求?
飞行前请求将具有 OPTIONS 方法,以便您识别它
,使用 async/await
语法使其变得简单。
避免将 async/await
与 then/catch
样式混合使用。
const getDataResponses = await Promise.all([
fetchClient.getData(
getEndpoint(
`amount=${countValues[0]}&difficulty=easy&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[1]}&difficulty=medium&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[2]}&difficulty=hard&type=${questionType}`
)
),]);
const data = await Promise.all(
getDataResponse.map((response) => {
return fetchClient.processData(response,"results");
})
);
console.log('getDataResponses',getDataResponses);
console.log('processDataResponse',data);
return [...data[0],...data[1],...data[2]];
,
由于 result
直接从 await
上的 Promise
获取值,因此您可以使用它代替 .then()
。
const responses = await Promise.all([
fetchClient.getData(
getEndpoint(
`amount=${countValues[0]}&difficulty=easy&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[1]}&difficulty=medium&type=${questionType}`
)
),fetchClient.getData(
getEndpoint(
`amount=${countValues[2]}&difficulty=hard&type=${questionType}`
)
),])
console.log('responses',responses);
const data = await Promise.all(
responses.map(function (response,idx) {
return fetchClient.processData(response,"results");
})
);
console.log('data',data);
console.log([...data[0],...data[2]]);
,
其他答案显示了如何更正代码,同时避免混合使用承诺链和 await
运算符。这个答案是关于 result
的未定义值出现的原因:
const result = await <promise chain>
在执行 result
操作数之前为 await
创建一个绑定。像所有简单的变量定义一样,它以 undefined
的值开始,并且因为它现在存在,所以在后面的代码中访问 result
不会产生错误。
promise 链的对象值是链中调用的最后一个promise 方法(即then
、catch
或finally
)返回的promise。这是对 await
操作数在返回其(成功)值作为 await
表达式的值之前等待结算的承诺。
因此 await
直到最后一个 result
处理程序返回后才会返回要分配给 then
的值,这意味着在
.then(function (data) {
console.log(data);
console.log(result); // returns undefined
return [...data[0],...data[2]];
});
已完成执行并返回。在此之前,所有 console.log(result)
调用都记录 undefined
,因为没有分配给 result
。
TLDR;
附加到 Promise 的处理程序异步执行,在它们附加到的 Promise 完成或被拒绝后,在事件循环的新调用中执行。
await
是一个一元运算符,能够保存执行状态并返回到事件循环,直到它的 promise 操作数变得稳定。
贴出代码的操作顺序是
定义
result
,将其初始化为undefined
,并设置await
操作符获取步骤5中then
返回的promise结果。-
发出三个端点数据请求。
-
使用
Promise.all
获取第 2 步的响应数组。 -
(然后)使用
Promise.all
从第 3 步的结果中异步获取数组中每个响应的过程数据数组。 -
(然后)将第 4 步中的数据数组展平并返回展平后的数组
-
(然后)
await
操作符获取第 5 步结果的回调,并将其作为await
表达式的值返回 -
从第 6 步返回的值用于初始化
const result
声明。从语法上讲,这发生在const result
语句结束之前,但实际上已经扩展到多个网络请求和事件循环调用所需的时间。