nodejs中async函数与callbacks

One limitation of async functions is that await only affects the directly surrounding async function. Therefore, an async function can’t await in a callback (however, callbacks can be async functions themselves, as we’ll see later on). That makes callback-based utility functions and methods tricky to use. Examples include the Array methods map() and forEach().

Let’s start with the Array method map(). In the following code, we want to download the files pointed to by an Array of URLs and return them in an Array.

async function downloadContent(urls) {
    return urls.map(url => {
        // Wrong syntax!
        const content = await httpGet(url);
        return content;
    });
}

This does not work, because await is syntactically illegal inside normal arrow functions. How about using an async arrow function, then?

async function downloadContent(urls) {
    return urls.map(async (url) => {
        const content = await httpGet(url);
        return content;
    });
}

There are two issues with this code:

  • The result is now an Array of Promises, not an Array of strings.
  • The work performed by the callbacks isn’t finished once map() is finished, because await only pauses the surrounding arrow function and httpGet() is resolved asynchronously. That means you can’t use await to wait until downloadContent() is finished.

We can fix both issues via Promise.all(), which converts an Array of Promises to a Promise for an Array (with the values fulfilled by the Promises):

async function downloadContent(urls) {
    const promiseArray = urls.map(async (url) => {
        const content = await httpGet(url);
        return content;
    });
    return await Promise.all(promiseArray);
}

The callback for map() doesn’t do much with the result of httpGet(), it only forwards it. Therefore, we don’t need an async arrow function here, a normal arrow function will do:

async function downloadContent(urls) {
    const promiseArray = urls.map(
        url => httpGet(url));
    return await Promise.all(promiseArray);
}

There is one small improvement that we still can make: This async function is slightly inefficient – it first unwraps the result of Promise.all() via await, before wrapping it again via return. Given that return doesn’t wrap Promises, we can return the result of Promise.all() directly:

async function downloadContent(urls) {
    const promiseArray = urls.map(
        url => httpGet(url));
    return Promise.all(promiseArray);
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容