13

我目前正在编写供个人使用的小型 NodeJS CLI 工具,并且我决定尝试使用 Babel 的 ES7 async/await 功能。

这是一个网络工具,所以我显然有异步网络请求。我为包写了一个简单的包装器request

export default function(options) {
    return new Promise(function(resolve, reject) {
        request({...options,
            followAllRedirects: true,
            headers: {
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
            }
        }, (error, response, body) => {
            if(error) {
                return reject(error);
            }
            resolve({response: response, body: body});
        });
    });
}

现在我可以做类似的事情

async function getGooglePage() {
    try {
        var r = await request({url: "http://google.com"});

        console.log(r.body);
        console.log("This will be printed in the end.")
    } catch(e) {
        console.log(e);
    }
}
getGooglePage();

现在我有一个问题:我在很多地方都提出了请求,我必须将所有这些功能标记为async,这是一个好习惯吗?我的意思是我的代码中几乎每个函数都应该是async因为我需要await其他async函数的结果。这就是为什么我认为我误解了 async/await 概念。

4

3 回答 3

12

async/await 有时被称为“传染性”或“病毒性”(或在 C# 世界中如此),因为为了使其有效,它需要在调用链的整个过程中得到支持。强制异步执行同步可能会导致意想不到的结果,因此您应该将其从原始方法一直扩展到使用它的顶级使用者。换句话说,如果您创建或使用了一个使用它的类型,那么该类型也应该实现它,依此类推。所以是的,预计您将 async 添加到本身依赖它的每个函数中。但是请注意,您不应将抢先添加异步添加到实际上不实现或不需要它的函数中。

试想:如果你使用asyncawait我的意思是 ing 一些东西),你就是async. 避免将async调用压缩成同步的东西。

于 2016-02-13T13:32:32.350 回答
6

我在很多地方都做了请求,我必须将所有这些功能标记为异步

是的,如果您的所有代码都是异步的,那么您将async在任何地方使用函数。

让你的所有代码都是异步的,但是事情变得复杂了。你必须担心任何地方的竞争条件,确保正确处理可重入函数,并记住在每个await基本上任何事情都可能发生。

我的意思是我的代码中几乎每个函数都应该是异步的,因为我需要等待其他异步函数的结果。

这可能不是最佳做法。您可以尝试将代码分解为更小的单元,其中大多数通常不是异步的。所以不要写

async function getXandThenDoY(xargs) {
    let res = await get(xargs);
    …
    return …;
}

你应该考虑做两个功能

function doY(res) {
    // synchronous
    …
    return …;
}
function getXandDoY(xargs) {
    // asynchronous
    return get(xargs).then(doY);
}
/* or, if you prefer:
async function getXandDoY(xargs) {
    return doY(await get(xargs));
}
*/
于 2016-02-13T13:36:47.060 回答
2

我也有同样的问题

并在这里找到了一个很好的答案→“陷阱 3:你的整个堆栈需要异步”</p>

不,async/await不会传染。(我也相信同样的事情有一段时间了)

您始终可以将同步函数的结果视为承诺,然后您就会恢复正常。

来自 developer.mozilla.org:

async 函数声明定义了一个异步函数……</p>

Return value: A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.

Sample code:

const log = console.log; // just lazy shorthand

// just to delay, as seen in many places
function promiseTimeout(time, value) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() { resolve(value); }, time);
    });
};

// the thing you care about
async function foo() {
    Promise.resolve('here')
    .then((a) => {log('doing stuff '+a); return 'pear'})
    .then(function(v) {
        return promiseTimeout(1000,v)
    });
};

// treat async-function like promise:
foo().then(function(){ log('folling up in main, ')});
// log('bad end');

gets you:

doing stuff here
following up in main

Enabling 'bad end' would show up too early. You can only await stuff it you use await. (And if you do, remember: It's just syntactic sugar, saving you of stuffing your follow-up code into .then() clasuses... nice, but no more than that.)

于 2018-04-17T06:21:08.497 回答