异步功能与等待 [英] Async functions vs await

查看:146
本文介绍了异步功能与等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我来自PHP背景,我正在尝试学习NodeJS。



我知道Node中的所有东西都是异步但我发现我在我的代码中我一直在使用async / await组合,我想确保我没有做一些愚蠢的事情。



它的原因是在很多情况下,我需要某些事情的结果才会继续(例如,对于一个小的ajax请求)。这个小的ajax请求没有别的目的,除了做我想要它的东西以及我指定的顺序,所以即使我做异步方式并使用回调写我仍然有等待事情以正确的顺序完成。



现在每当我发现自己处于这种情况时,我只是等待等待结果:



ie:

  var result = await this.doSomething(data); 

反对使用回调

  this.doSomething(数据,函数(回调){
//代码
回调();
});

对我而言,第一个例子看起来比第二个更干净,这就是为什么我一直在选择那个。但是我担心我可能会遗漏一些基本的东西。但是在异步调用下没有其他任何东西要处理的情况下,事情进展的唯一方法就是它遵循同步风格,在第二种风格中使用第一种风格是否有什么问题?

解决方案


但我担心我可能会遗漏一些基本的东西。


不,你不是,这正是你想要做的,假设 this.doSomething(data)是异步(如果它是一个ajax调用,希望它是异步的)并且它返回一个promise(使用 async 关键字定义的所有函数都隐式执行)。 (如果它不是异步的,你不需要等待,虽然它是允许的。)



你是事情正在经历转型,这可能有点混乱(可以理解)。直到最近,Node API(内置的和第三方模块提供的)的压倒性惯例是使用节点回调模式,这是一个将进行异步工作的函数,它的最后一个参数是一个回调函数,它将调用第一个参数指示成功/失败( null =成功,其他任何东西都是错误对象),后续参数提供结果。 (你的第二个例子假设 doSomething 是其中之一,而不是一个返回一个promise的函数。)



示例: fs.readFile ,您可以这样使用:

  fs .readFile(/ some / file,utf-8,function(err,data){
if(err){
// ...处理错误发生的事实..
return;
}
// ...使用数据...
});

这种风格很快导致回调地狱,这是承诺的原因之一(又名期货) )是发明的。



很多的Node API仍然使用旧模式。



如果您需要使用节点回调 - 模式功能,您可以使用 util.promisify 创建启用许可的版本。例如,假设您需要使用 fs.readFile ,它使用Node回调模式。您可以获得这样的承诺版本:

  const readFilePromise = util.promisify(fs.readFile); 

...然后将其与 async一起使用 / await 语法(或直接通过然后使用承诺):

  const data = await readFilePromise(/ some / file,utf-8); 

还有一个名为 npm 模块href =https://www.npmjs.com/package/promisify =nofollow noreferrer> promisify 可提供承诺版本一整个API。 (可能不止一个。)



仅仅因为承诺和 async / 等待在大多数情况下替换旧的Node回调样式并不意味着回调仍然没有位置:承诺只能一次。他们是一次性的事情。所以回调仍然有一个位置,例如方法 EventEmitters ,就像一个可读的流:

  fs.createReadStream(/ some / file ,utf-8)
.on(data,chunk => {
// ...用大块数据做某事...
})
.on(end,()=> {
// ...对达到流末尾的事实做了些事......
});

由于数据将多次触发,因此为它使用回调是有意义的;承诺不适用。



另请注意,您只能在 await > async 功能。因此,您可能会发现自己习惯于主要模块结构,看起来像这样:

  //。 ..Setup(`require`调用,`import`一旦支持等等)... 
(async()=> {
//代码可以使用`await` here .. 。
})()。catch(err => {
//处理代码顶级发生错误/承诺拒绝的事实
});

如果你离开 catch 希望您的脚本在未处理的错误/拒绝时终止。 (Node还没有这样做,但是一旦未处理的拒绝检测成熟了。)



或者,如果你想在非non中使用一个启用promise的函数 async 功能,只需使用然后 catch

  this.doSomething()
.then(result => {
//使用结果
})
.catch(err => {
//处理错误
});






注意:<节点7.x及更高版本中直接支持code> async / 等待。如果您打算使用 async / 等待,请确保您的目标生产环境支持Node 7.x或更高版本。如果没有,您可以使用 Babel 之类的内容来转换代码,然后在旧版本的Node上使用转换后的结果。 / p>

I'm coming from a PHP background and I'm trying to learn NodeJS.

I know that everything in Node is async but I've found that i've been using the async / await combo quite a lot in my code and I wanted to make sure I wasn't doing something stupid.

The reason for it is that I have a lot of situations where I need the result of something before continuing (for example for a small ajax request). This small ajax request has no other purpose other than to do the set of things that I want it to and in the order that I specify so even if I do things the "async way" and write it using a callback i'm still having to wait for things to finish in the right order.

Right now whenever I find myself in this situation I just use await to wait for the result:

ie:

var result = await this.doSomething(data);

Opposed to using a callback

this.doSomething(data, function(callback) {
  // code
  callback();
});

To me the first example looks cleaner than the second one which is why I've been opting for that. But I'm worried that I might be missing something fundamental here. But in a situation where there is nothing else to process below the async call and the only way for things to progress is for it to follow a syncronous style, is there anything wrong with using the first style over the second?

解决方案

But I'm worried that I might be missing something fundamental here.

Nope, you're not, that's exactly what you want to do, assuming this.doSomething(data) is asynchronous (and if it's an ajax call, one hopes it is async) and that it returns a promise (which all functions defined with the async keyword do implicitly). (If it's not asynchronous, you don't need the await, although it's allowed.)

You're probably being a bit confused (understandably) by the fact that things are going through a transition. Until recently, the overwhelming convention in Node APIs (the built-in ones and ones provided by third-party modules) was to use the "Node callback" pattern, which is that a function that will do asynchronous work expects its last argument to be a callback, which it will call with a first argument indicating success/failure (null = success, anything else is an error object) with subsequent arguments providing the result. (Your second example assumes doSomething is one of these, instead of being a function that returns a promise.)

Example: fs.readFile, which you use like this:

fs.readFile("/some/file", "utf-8", function(err, data) {
    if (err) {
        // ...handle the fact an error occurred..
        return;
    }
    // ...use the data...
});

This style quickly leads to callback hell, though, which is one of the reasons promises (aka "futures") were invented.

But a lot of Node APIs still use the old pattern.

If you need to use "Node callback"-pattern functions, you can use util.promisify to create promise-enabled versions of them. For instance, say you need to use fs.readFile, which uses the Node callback pattern. You can get a promise version like this:

const readFilePromise = util.promisify(fs.readFile);

...and then use it with async/await syntax (or use the promise directly via then):

const data = await readFilePromise("/some/file", "utf-8");

There's also an npm module called promisify that can provide a promise-ified version of an entire API. (There's probably more than one.)

Just because promises and async/await replace the old Node callback style in most cases doesn't mean callbacks don't still have a place: A Promise can only be settled once. They're for one-off things. So callbacks still have a place, such as with the on method of EventEmitters, like a readable stream:

fs.createReadStream("/some/file", "utf-8")
    .on("data", chunk => {
        // ...do something with the chunk of data...
    })
    .on("end", () => {
        // ...do something with the fact the end of the stream was reached...
    });

Since data will fire multiple times, it makes sense to use a callback for it; a promise wouldn't apply.

Also note that you can only use await in an async function. Consequently, you may find yourself getting into the habit of a "main" module structure that looks something like this:

// ...Setup (`require` calls, `import` once it's supported, etc.)...
(async () => {
    // Code that can use `await `here...
})().catch(err => {
    // Handle the fact an error/promise rejection occurred in the top level of your code
});

You can leave the catch off if you want your script to terminate on an unhandled error/rejection. (Node doesn't do that yet, but it will once unhandled rejection detection matures.)

Alternately, if you want to use a promise-enabled function in a non-async function, just use then and catch:

this.doSomething()
    .then(result => {
        // Use result
    })
    .catch(err => {
        // Handle error
    });


Note: async/await is directly supported in Node 7.x and above. Be sure your target production environment supports Node 7.x or above if your'e going to use async/await. If not, you could transpile your code using something like Babel and then use the transpiled result on the older version of Node.

这篇关于异步功能与等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆