async/await 函数中的 JavaScript Promise 解析最终响应数组
Posted
技术标签:
【中文标题】async/await 函数中的 JavaScript Promise 解析最终响应数组【英文标题】:JavaScript Promise inside async/await function resolve final array of responses 【发布时间】:2019-04-24 19:39:14 【问题描述】:我是 javascript 和 Promises 的新手。 我正在尝试构建从 API 获取的对象数组。
为此,我在文件MyFile.js
中构建了两个函数。
当 axios 承诺被解决时,第一个返回一个承诺。这是
function get_items (url)
return new Promise((resolve, reject) =>
let options =
baseURL: url,
method: 'get'
axios(options)
.then(response =>
resolve(response.data)
)
.catch(error =>
reject(error.stack)
)
)
第二个是这样的:
let output = []
let next_url = 'https://some_url.com/api/data'
async function get_data ()
try
let promise = new Promise((resolve, reject) =>
if (next_url)
get_items(next_url)
.then(response =>
output.push(...response.results)
if (response.next)
next_url = response.next
console.log('NEXT_URL HERE', next_url)
get_data()
else
console.log('else')
next_url = false
get_data()
)
.catch(error =>
reject(error.stack)
)
else
console.log('before resolve')
resolve(output)
)
return await promise
catch(e)
console.log(e)
这是我磨牙的地方。 我认为我对这个功能的理解是:
它返回了一个承诺的价值(这就是我理解return await promise
正在做的事情)
这是一个递归函数。因此,如果有 next_url,则函数继续执行。但是如果没有,它会被最后一次调用以进入else
部分,在该部分中它解析数组output
,其中包含所有承诺的结果(值而不是状态)。至少,当我执行它并使用我写的 console.log
检查我的健全性检查时,它可以工作。
所以,output
充满了数据,这很棒。
但是,当我从另一个文件MyOtherFile.js
调用这个函数时,像这样:
final_output = []
MyFile.get_data()
.then(result =>
console.log('getting data')
final_output.push(...result)
)
它永远不会进入then
部分。当我 console.log MyFile.get_data()
时,这是一个未决的承诺。
所以,我想做的是能够让get_data()
等待所有的承诺结果(不使用 Promise.all(),进行连续调用,而不是并行调用,这对表演,我猜?)然后能够在从其他任何地方调用此函数时在then
部分中检索该响应。
请记住,总的来说,我是 Promise 和 JavaScript 的新手(我更喜欢 Python)。
如果我的问题不够清楚,请告诉我。 这两天摸不着头脑,感觉自己在绕圈跑。
感谢您成为一个很棒的社区!
【问题讨论】:
避免Promise
constructor antipattern!
【参考方案1】:
这有点未经测试
const api_url = 'https://some_url.com/api/data';
get_data(api_url).then((results) =>
console.log(results);
).catch((error) =>
// console.error(error);
);
function get_items (url)
const options =
baseURL: url,
method: 'get'
;
return axios(options).then((response) => response.data);
async function get_data(next_url)
const output = [];
while (next_url)
const results, next = await get_items(next_url);
output.push(...results);
next_url = next;
return output;
基本上它使事情变得更整洁。我建议查看更多有关 Promises 的示例以及优势以及何时缓解等待/异步。需要记住的一件事是,如果您返回一个 Promise,它将遵循整个 then
链,并且它将始终返回一个值为最后一个 then
.. 的 Promise,如果这有意义:)
【讨论】:
【参考方案2】:有几个问题。一个是你永远不会 resolve
初始 Promise
除非输入 else
块。另一个是您应该每次返回递归get_data
调用,以便它可以与初始Promise
正确链接。您也可以考虑避免explicit promise construction antipattern - get_items
已经返回Promise
,因此无需构造另一个(get_items
内部相同,axios
调用也返回Promise
s)。
您可以考虑一个普通的while
循环,重新分配next_url
字符串,直到它是假的:
function get_items (baseURL)
const options =
baseURL: url,
method: 'get'
// return the axios call, handle errors in the consumer instead:
return axios(options)
.then(res => res.data)
async function get_data()
const output = []
let next_url = 'https://some_url.com/api/data'
try
while (next_url)
const response = await get_items(next_url);
output.push(...response.results)
next_url = response.next;
catch (e)
// handle errors *here*, perhaps
console.log(e)
return output;
注意.catch
将导致Promise
从拒绝 Promise
转换为已解决 - 你不想@987654338 @ 无处不在,因为这会使调用者难以检测到错误。
【讨论】:
【参考方案3】:另一种方法是根本不使用 async,而只是递归地返回一个 Promise:
const getItems = (url) =>
axios(
baseURL: url,
method: 'get',
).then((response) => response.data);
const getData = (initialUrl) =>
const recur = (result, nextUrl) =>
!nextUrl
? Promise.resolve(result)
: getItems(nextUrl).then((data) =>
recur(result.concat([data.results]), data.next),
);
return recur([],initialUrl)
.catch(e=>Promise.reject(e.stack));//reject with error stack
;
正如CertainPerformance 指出的那样;您不需要在每个级别都捕获,如果您希望 getData 使用 error.stack 拒绝,您只需捕获一次。
但是;如果您有 100 个下一个 url,其中 99 个很好,但只有最后一个失败了,您想以一种保持结果的方式拒绝,以便您可以再试一次?
如果你这样做了,那么代码可能看起来像这样:
const getData = (initialUrl) =>
const recur = (result, nextUrl) =>
!nextUrl
? Promise.resolve(result)
: getItems(nextUrl)
.catch(e=>Promise.reject([e,result]))//reject with error and result so far
.then((data) =>
recur(result.concat([data.results]), data.next),
);
return recur([],initialUrl);//do not catch here, just let it reject with error and result
;
【讨论】:
以上是关于async/await 函数中的 JavaScript Promise 解析最终响应数组的主要内容,如果未能解决你的问题,请参考以下文章
async/await 函数中的 JavaScript Promise 解析最终响应数组
从 Nodejs 中的 mySQL 获取数据时如何从 Async/await 函数获取返回值