Postponing .then() calls on a Promise returned from an async JavaScript function until after multiple awaits have run inside the function

huangapple go评论63阅读模式
英文:

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 &#39;uri2&#39; will only be processed after all pages of &#39;uri1&#39; 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(&#39;uri1&#39;).then(() =&gt; f(&#39;uri2&#39;))

async function g(initialPageUri, then) {
  let nextPageUri = initialPageUri
  while (nextPageUri) {
    const o = await getObjectFromJsonFromUri(nextPageUri)
    // do stuff with o
    nextPageUri = o.nextPageUri
  }
  then()
}

g(&#39;uri1&#39;, () =&gt; g(&#39;uri2&#39;, () =&gt; {}))

Simplified logging from my real code: &lt;url letter&gt; &lt;page number or _ if no more pages&gt; 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) =&gt; {
    setTimeout(resolve, msec);
  });
}

let pages = 0;

async function getObjectFromJsonFromUri(uri) {
  console.log(&#39;requesting &#39;, uri);
  await delay(1000);
  return {
    nextPageUri: pages-- &gt; 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(&#39;uri1&#39;).then(() =&gt; f(&#39;uri2&#39;));

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月26日 13:28:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76337880.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定