JS异步函数以随机顺序执行
JS async functions execute in random order
我有一个异步函数发出 api 请求。完成后,它会调用一个不同的异步函数,发出 4 次 api 请求(旨在按调用顺序进行)。但每次运行时,那些 api 请求 return 随机顺序的数据。
首先,我调用 fetchSearch
,这按预期工作。
const fetchSearch = async () => {
var myHeaders = new Headers();
myHeaders.append("x-app-id", "...");
myHeaders.append("x-app-key", "...");
var requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => (
handleSearch(JSON.parse(result).common)
)
)
.catch(error => console.log('error', error));
}
这调用了handleSearch
。我可能在这里做错了什么。
const handleSearch = (data) => {
const dataList=[]
for (var key in data) {
if (data.hasOwnProperty(key)) {
dataList.push(data[key])
}
}
if (dataList[0] !== undefined) {
setSearchResults([dataList[0], dataList[1], dataList[2], dataList[3]])
fetchNutrition(dataList[0].food_name)
.then(() => {fetchNutrition(dataList[1].food_name)})
.then(() => {fetchNutrition(dataList[2].food_name)})
.then(() => {fetchNutrition(dataList[3].food_name)})
} else {
setSearchError(true)
}
}
handleSearch
呼叫 fetchNutrition
:
const fetchNutrition = async (foodName) => {
var h = new Headers();
h.append("accept", "application/json");
h.append("x-app-id", "...");
h.append("x-app-key", "...");
h.append("x-remote-user-id", "1");
h.append("Content-Type", "application/json");
var requestOptions = {
method: 'POST',
headers: h,
body: JSON.stringify({ "query": foodName }),
redirect: 'follow'
}
await fetch("https://trackapi.nutritionix.com/v2/natural/nutrients", requestOptions)
.then(response => response.text())
.then(result => {setNutritionResults(nutritionResults => [...nutritionResults, JSON.parse(result)])})
.catch(error => console.log('error', error))
}
对于来自 fetchSearch
、handleSearch
和 fetchNutrition
的 4 个字符串的数组,应该遍历每个字符串并将相应的营养 JSON 字符串添加到 nutritionResults
数组状态(在数组中的顺序正确)。
每次运行时,所有营养结果都会 return 在 nutritionResults
数组中以随机顺序编辑,我假设这是因为 handleSearch
没有调用正确顺序的功能。或者我遗漏了另一个问题。
例如,如果 fetchSearch
returns ["apple", "apples", "apple juice", "apple pie"]
,nutritionResults
将以长度为 4 的数组结束,但每次运行时顺序随机。
我认为你使用 await 比 promise.then 更短。
试试这个:
const handleSearch = async (data) => {
...
await fetchNutrition(dataList[1].food_name)
await fetchNutrition(dataList[2].food_name)
await fetchNutrition(dataList[3].food_name)
...
}
问题是 handleSearch()
不是 await
ing fetchNutrition()
。因此,代码无需等待即可继续运行 - 与描述的完全一样。
要解决此问题,您需要做的就是等待 fetchNutrition()
完成:
const handleSearch = async (data) => {
// ...
await fetchNutrition(dataList[0].food_name)
.then(() => {return fetchNutrition(dataList[1].food_name)})
.then(() => {return fetchNutrition(dataList[2].food_name)})
.then(() => {return fetchNutrition(dataList[3].food_name)})
// ...
}
注意:fetchNutrution()
前面的return
很重要,如果你想让await
等待它完成。否则await
不会等待,因为没有Promise
return被.then()
.
链
或者这做完全相同的事情:
const handleSearch = (data) => {
// ...
return fetchNutrition(dataList[0].food_name)
.then(() => {return fetchNutrition(dataList[1].food_name)})
.then(() => {return fetchNutrition(dataList[2].food_name)})
.then(() => {return fetchNutrition(dataList[3].food_name)})
// NOTE: The bugfix is adding a "return"
// ...
}
以上任何一项都会导致 handleSearch()
到 return 一个可以等待的 Promise。
现在您还需要允许 fetchSearch()
到 await
handleSearch()
。与上面类似,您可以添加一个 return
来执行此操作:
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => (
return handleSearch(JSON.parse(result).common)
// Note: The bugfix is adding the return above
// so that this chain of .then() will return the
// handleSearch() Promise which the above await
// will wait for
)
)
或者您也可以执行以下操作以允许 fetchSearch()
等待 handleSearch()
:
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => handleSearch(JSON.parse(result).common)
)
// Note: The bugfix is removing the braces "()" around
// handleSearch() causing js to add an implicit "return"
另一种选择是避免将 async/await 与 .then() 链完全混合:
const response = await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
const result = await response.text()
await handleSearch(JSON.parse(result).common)
我有一个异步函数发出 api 请求。完成后,它会调用一个不同的异步函数,发出 4 次 api 请求(旨在按调用顺序进行)。但每次运行时,那些 api 请求 return 随机顺序的数据。
首先,我调用 fetchSearch
,这按预期工作。
const fetchSearch = async () => {
var myHeaders = new Headers();
myHeaders.append("x-app-id", "...");
myHeaders.append("x-app-key", "...");
var requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => (
handleSearch(JSON.parse(result).common)
)
)
.catch(error => console.log('error', error));
}
这调用了handleSearch
。我可能在这里做错了什么。
const handleSearch = (data) => {
const dataList=[]
for (var key in data) {
if (data.hasOwnProperty(key)) {
dataList.push(data[key])
}
}
if (dataList[0] !== undefined) {
setSearchResults([dataList[0], dataList[1], dataList[2], dataList[3]])
fetchNutrition(dataList[0].food_name)
.then(() => {fetchNutrition(dataList[1].food_name)})
.then(() => {fetchNutrition(dataList[2].food_name)})
.then(() => {fetchNutrition(dataList[3].food_name)})
} else {
setSearchError(true)
}
}
handleSearch
呼叫 fetchNutrition
:
const fetchNutrition = async (foodName) => {
var h = new Headers();
h.append("accept", "application/json");
h.append("x-app-id", "...");
h.append("x-app-key", "...");
h.append("x-remote-user-id", "1");
h.append("Content-Type", "application/json");
var requestOptions = {
method: 'POST',
headers: h,
body: JSON.stringify({ "query": foodName }),
redirect: 'follow'
}
await fetch("https://trackapi.nutritionix.com/v2/natural/nutrients", requestOptions)
.then(response => response.text())
.then(result => {setNutritionResults(nutritionResults => [...nutritionResults, JSON.parse(result)])})
.catch(error => console.log('error', error))
}
对于来自 fetchSearch
、handleSearch
和 fetchNutrition
的 4 个字符串的数组,应该遍历每个字符串并将相应的营养 JSON 字符串添加到 nutritionResults
数组状态(在数组中的顺序正确)。
每次运行时,所有营养结果都会 return 在 nutritionResults
数组中以随机顺序编辑,我假设这是因为 handleSearch
没有调用正确顺序的功能。或者我遗漏了另一个问题。
例如,如果 fetchSearch
returns ["apple", "apples", "apple juice", "apple pie"]
,nutritionResults
将以长度为 4 的数组结束,但每次运行时顺序随机。
我认为你使用 await 比 promise.then 更短。 试试这个:
const handleSearch = async (data) => {
...
await fetchNutrition(dataList[1].food_name)
await fetchNutrition(dataList[2].food_name)
await fetchNutrition(dataList[3].food_name)
...
}
问题是 handleSearch()
不是 await
ing fetchNutrition()
。因此,代码无需等待即可继续运行 - 与描述的完全一样。
要解决此问题,您需要做的就是等待 fetchNutrition()
完成:
const handleSearch = async (data) => {
// ...
await fetchNutrition(dataList[0].food_name)
.then(() => {return fetchNutrition(dataList[1].food_name)})
.then(() => {return fetchNutrition(dataList[2].food_name)})
.then(() => {return fetchNutrition(dataList[3].food_name)})
// ...
}
注意:fetchNutrution()
前面的return
很重要,如果你想让await
等待它完成。否则await
不会等待,因为没有Promise
return被.then()
.
或者这做完全相同的事情:
const handleSearch = (data) => {
// ...
return fetchNutrition(dataList[0].food_name)
.then(() => {return fetchNutrition(dataList[1].food_name)})
.then(() => {return fetchNutrition(dataList[2].food_name)})
.then(() => {return fetchNutrition(dataList[3].food_name)})
// NOTE: The bugfix is adding a "return"
// ...
}
以上任何一项都会导致 handleSearch()
到 return 一个可以等待的 Promise。
现在您还需要允许 fetchSearch()
到 await
handleSearch()
。与上面类似,您可以添加一个 return
来执行此操作:
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => (
return handleSearch(JSON.parse(result).common)
// Note: The bugfix is adding the return above
// so that this chain of .then() will return the
// handleSearch() Promise which the above await
// will wait for
)
)
或者您也可以执行以下操作以允许 fetchSearch()
等待 handleSearch()
:
await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
.then(response => response.text())
.then(
result => handleSearch(JSON.parse(result).common)
)
// Note: The bugfix is removing the braces "()" around
// handleSearch() causing js to add an implicit "return"
另一种选择是避免将 async/await 与 .then() 链完全混合:
const response = await fetch(`https://trackapi.nutritionix.com/v2/search/instant?query=${search}`, requestOptions)
const result = await response.text()
await handleSearch(JSON.parse(result).common)