我来自PHP背景,我正在尝试学习NodeJS。
我知道Node中的所有内容都是异步的,但我发现我的代码中已经使用了异步/等待组合,并且我想确保我不做有点蠢。
原因是我有很多情况需要需要某些事情才能继续(例如对于一个小的ajax请求)。这个小的ajax请求没有其他目的,除了做我想要它的东西以及我指定的顺序,所以即使我做了事情"异步方式"并使用回调来编写它,我仍然需要等待以正确的顺序完成任务。
现在每当我发现自己处于这种情况时,我只是等待等待结果:
即:
var result = await this.doSomething(data);
反对使用回调
this.doSomething(data, function(callback) {
// code
callback();
});
对我而言,第一个例子看起来比第二个例子更清晰,这就是为什么我一直在选择这个。但是我担心我可能会遗漏一些基本的东西。但是在异步调用下没有其他任何东西可以处理的情况下,事情进展的唯一方法就是它遵循同步风格,在第二种风格中使用第一种风格有什么不对吗?
答案 0 :(得分:6)
但我担心我可能会遗漏一些基本的东西。
不,你不是,这正是你想要做的,假设this.doSomething(data)
是异步的(如果它是一个ajax调用,人们希望它是异步的)并且它返回一个promise(使用async
关键字定义的所有函数都隐式执行)。 (如果它不是异步的,你不需要await
,虽然它是允许的。)
事情正在经历转型,你可能会感到有点困惑(可以理解)。直到最近,Node API(内置的和第三方模块提供的)的压倒性惯例是使用" Node回调"模式,这是一个将进行异步工作的函数,它的最后一个参数是一个回调函数,它将调用第一个参数来指示成功/失败(null
=成功,其他任何东西都是错误对象)提供结果的后续论据。 (你的第二个例子假设doSomething
是其中之一,而不是一个返回一个promise的函数。)
示例:fs.readFile
,您可以这样使用:
fs.readFile("/some/file", "utf-8", function(err, data) {
if (err) {
// ...handle the fact an error occurred..
return;
}
// ...use the data...
});
这种风格很快就会导致回调地狱,这也是承诺(又名" future")被发明的原因之一。
但很多的Node API仍然使用旧模式。
如果您需要使用"节点回调" -pattern函数,您可以使用util.promisify
创建启用了承诺的版本。例如,假设您需要使用fs.readFile
,它使用Node回调模式。您可以获得这样的承诺版本:
const readFilePromise = util.promisify(fs.readFile);
...然后将其与async
/ await
语法一起使用(或直接通过then
使用承诺):
const data = await readFilePromise("/some/file", "utf-8");
还有一个名为promisify
的npm
模块可以提供整个API的承诺版本。 (可能不止一个。)
仅仅因为承诺和async
/ await
在大多数情况下取代旧的Node回调风格并不意味着回调不会占有一席之地:承诺只能解决的一次即可。他们是一次性的事情。所以回调仍然有一个位置,例如使用EventEmitters的on
方法,就像一个可读的流:
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...
});
由于data
会多次触发,因此对它使用回调是有意义的;承诺不适用。
另请注意,您只能在await
功能中使用async
。因此,你可能会发现自己养成了一个主要的习惯。模块结构看起来像这样:
// ...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
});
如果您希望脚本以未处理的错误/拒绝终止,您可以将catch
关闭。 (Node还没有做到这一点,但是一旦未处理的拒绝检测成熟了。)
或者,如果您想在非async
函数中使用启用承诺的函数,只需使用then
和catch
:
this.doSomething()
.then(result => {
// Use result
})
.catch(err => {
// Handle error
});
注意:节点7.x及更高版本中直接支持async
/ await
。如果您要使用async
/ await
,请确保您的目标制作环境支持Node 7.x或更高版本。如果没有,您可以使用Babel之类的内容来转换代码,然后在旧版本的Node上使用转换后的结果。