英文:
Postponing .then() calls on a Promise returned from an async JavaScript function until after multiple awaits have run inside the function
问题
I am using an asynchronous JavaScript http client to download & process some paged JSON data from an initial URI & subsequent page URIs.
Each JSON page includes the URI for the next page, if there are more pages.
Sometimes, I need to process all pages for an initial URI & its subsequent page URIs before progressing to the next completely new initial URI.
I'd prefer to use await
calls to the async http client to handle the initial URI & all subsequent page URIs all within a single call to my own async
function (named f()
), calling .then()
on the Promise
returned from f()
to process a second initial URI only after the first initial URI & all of its pages have been downloaded & processed, rather than having to pass a callback to f()
that I must manually call at the end of f()
.
e.g., can f()
and/or the code that uses it below be modified such that 'uri2'
will only be processed after all pages of 'uri1'
have been processed without resorting to something like the manual callback mechanism in g()
?
async function f(initialPageUri) {
let nextPageUri = initialPageUri
while (nextPageUri) {
const o = await getObjectFromJsonFromUri(nextPageUri)
// do stuff with o
nextPageUri = o.nextPageUri
}
}
f('uri1').then(() => f('uri2'))
Simplified logging from my real code: <url letter> <page number or _ if no more pages>
in order of requesting:
A 1
A _
B 1
C 1
D 1
E 1
F 1
E _
D _
B 2
C _
F 2
B 3
F _
B _
英文:
I am using an asynchronous JavaScript http client to download & process some paged JSON data from an initial URI & subsequent page URIs.
Each JSON page includes the URI for the next page, if there are more pages.
Sometimes, I need to process all pages for an initial URI & its subsequent page URIs before progressing to the next completely new initial URI.
I'd prefer to use await
calls to the async http client to handle the initial URI & all subsequent page URIs all within an single call to my own async
function (named f()
), calling .then()
on the Promise
returned from f()
to process a second initial URI only after the first initial URI & all of its pages have been downloaded & processed, rather than having to pass a callback to f()
that I must manually call at the end of f()
.
e.g., can f()
and/or the code that uses it below be modified such that 'uri2'
will only be processed after all pages of 'uri1'
have been processed without resorting to something like the manual callback mechanism in g()
?
async function f(initialPageUri) {
let nextPageUri = initialPageUri
while (nextPageUri) {
const o = await getObjectFromJsonFromUri(nextPageUri)
// do stuff with o
nextPageUri = o.nextPageUri
}
}
f('uri1').then(() => f('uri2'))
async function g(initialPageUri, then) {
let nextPageUri = initialPageUri
while (nextPageUri) {
const o = await getObjectFromJsonFromUri(nextPageUri)
// do stuff with o
nextPageUri = o.nextPageUri
}
then()
}
g('uri1', () => g('uri2', () => {}))
Simplified logging from my real code: <url letter> <page number or _ if no more pages>
in order of requesting:
A 1
A _
B 1
C 1
D 1
E 1
F 1
E _
D _
B 2
C _
F 2
B 3
F _
B _
答案1
得分: 1
Your first solution should work as-is.
任何 async
函数默认返回一个 Promise。您可以像在您的第一个代码块中对 f
执行 .then
一样对 async
函数的结果执行 .then
。
另外,您可以在 async
函数上执行 await
,以等待 Promise
解决后再继续。这正是您在调用 getObjectFromJsonFromUri
时所做的。
快速演示:
function delay(msec) {
return new Promise((resolve) => {
setTimeout(resolve, msec);
});
}
let pages = 0;
async function getObjectFromJsonFromUri(uri) {
console.log('requesting ', uri);
await delay(1000);
return {
nextPageUri: pages-- > 0 ? `page${pages}` : null,
};
}
async function f(initialPageUri) {
pages = 2; // 模拟每个 uri 有 2 页
let nextPageUri = initialPageUri
while (nextPageUri) {
const output = await getObjectFromJsonFromUri(nextPageUri);
// 处理 output
nextPageUri = output.nextPageUri
}
}
f('uri1').then(() => f('uri2'));
(请注意:我已经翻译了代码块,不包括注释部分。)
英文:
Your first solution should work as-is.
Any async
function returns a Promise by default. You can do .then
on the result of the async
function as you do in your first block of code with f
.
Additionally, you can perform await
on async
functions to wait for the Promise
to resolve before continuing. That is exactly what you do in your call to getObjectFromJsonFromUri
.
Quick demo:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function delay(msec) {
return new Promise((resolve) => {
setTimeout(resolve, msec);
});
}
let pages = 0;
async function getObjectFromJsonFromUri(uri) {
console.log('requesting ', uri);
await delay(1000);
return {
nextPageUri: pages-- > 0 ? `page${pages}` : null,
};
}
async function f(initialPageUri) {
pages = 2; // simulate that each uri has 2 pages
let nextPageUri = initialPageUri
while (nextPageUri) {
const output = await getObjectFromJsonFromUri(nextPageUri);
// do stuff with output
nextPageUri = output.nextPageUri
}
}
f('uri1').then(() => f('uri2'));
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论