我担心我可能会错过一些基本的东西。
不,你没有错,这正是你想要做的,假设
this.doSomething(data)
是异步的(如果它是一个ajax调用,希望它是异步的),并且它返回一个promise(所有使用
async
关键字定义的函数都会隐式返回promise)。 (如果它不是异步的,则不需要
await
,尽管允许这样做。)
您可能会因事情正在经历转变而感到有点困惑(可以理解)。 直到最近,在Node API中(内置和由第三方模块提供的API)中,压倒性的约定是使用“Node回调”模式,即执行异步工作的函数期望其最后一个参数是回调函数,该函数将使用第一个参数指示成功/失败(
null
=成功,任何其他值均为错误对象),随后的参数提供结果。 (您的第二个示例假设
doSomething
是其中之一,而不是返回promise的函数。)
示例:
fs.readFile
,您可以像这样使用它:
fs.readFile("/some/file", "utf-8", function(err, data) {
if (err) {
return;
}
});
这种编程风格很容易导致回调地狱,这也是承诺对象(又称“未来对象”)被发明的原因之一。
但是,很多 Node API 仍然使用旧的模式。
如果您需要使用“Node 回调”模式函数,则可以使用
util.promisify
创建启用承诺对象的版本。例如,假设您需要使用使用 Node 回调模式的
fs.readFile
,则可以像这样获取承诺对象版本:
const readFilePromise = util.promisify(fs.readFile);
然后使用 async
/await
语法(或直接通过 then
使用 Promise)来使用它:
const data = await readFilePromise("/some/file", "utf-8");
还有一个名为 promisify
的 npm
模块,可以提供整个 API 的 Promise 版本。(可能不止一个)
仅仅因为 Promises 和 async
/await
在大多数情况下取代了旧的 Node 回调风格,并不意味着回调函数已经没有用处:Promise 只能被解决 一次。它们只适合一次性的事情。所以回调函数仍然有用处,例如在 EventEmitters 的 on
方法中,如可读流:
fs.createReadStream("/some/file", "utf-8")
.on("data", chunk => {
})
.on("end", () => {
});
由于data
会多次触发,因此使用回调函数是有意义的;Promise不适用。
另外请注意,您只能在async
函数中使用await
。因此,您可能会发现自己养成了一个类似于以下结构的“主”模块结构的习惯:
(async () => {
})().catch(err => {
});
你可以不使用
catch
,这样当出现未处理的错误/拒绝时,你的脚本就会终止。(Node目前还没有这样做,但一旦未处理的拒绝检测成熟,它就会这样做。)
或者,如果你想在非
async
函数中使用一个启用了promise的函数,只需使用
then
和
catch
:
this.doSomething()
.then(result => {
})
.catch(err => {
});
注意:在 Node 7.x 及以上版本中,直接支持使用
async
/
await
。如果要使用
async
/
await
,请确保目标生产环境支持 Node 7.x 或更高版本。否则,您可以使用类似
Babel 的工具对代码进行转译,然后在旧版本的 Node 上使用转译后的结果。
await
。请参考这里:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await - arbuthnott