Javascript : promise chain vs. async/await?



我正在学习JavascriptPromiseasync/await。下面的示例代码异步读取并解析 node.js(我的节点.js版本为 v10.0.0(中的 JSON 文件。

在示例代码中,ChainReadJson 函数和 AwaitReadJson 函数正在执行相同的操作,读取和分析 JSON 文件。不同之处在于 ChainReadJson 函数使用承诺链,而 AwaitReadJson 函数使用 async/await。

const FS = require("fs");
function ReadFile(fileName) {
return new Promise((Resolve, Reject) => {
FS.readFile(fileName, 'utf8', (error, result) => {
if (error)
Reject(error);
else
Resolve(result);
});
});
}
// function using promise chain
function ChainReadJson(fileName, CallBack) {
ReadFile(fileName)
.then(
res => JSON.parse(res),
err => {
Message(-1, err.message);
}
)
.then(
res => {
if (res !== undefined)
CallBack(fileName, res);
},
err => {
Message(-2, err.message);
}
);
}
// function using async/await
async function AwaitReadJson(fileName, CallBack) {
let res, json;
try {
res = await ReadFile(fileName);
}
catch (err) {
Message(-1, err.message);
return;
}
try {
json = JSON.parse(res);
}
catch (err) {
Message(-2, err.message);
return;
}
CallBack(fileName, json);
}
ChainReadJson('test.json', PrintJSON);
AwaitReadJson('test.json', PrintJSON);
// common functions
function PrintJSON(fileName, json) {
console.log(`JSON[${fileName}]:`, json);
}
function Message(n, str) {
console.log(`[${n}]`, str);
}

在使用承诺链为 ChainReadJson 函数编写代码时,我很难控制执行结果和错误。但是,当使用 async/await 为 AwaitReadJson 函数编写代码时,这些困难大多消失了。

我是否正确理解了异步/等待的好处?与承诺链相比,异步/等待的缺点是什么?

(示例代码是本答案中代码的修改版本。原始代码仅使用承诺链,并且编写时可以确切地知道错误在链中发生的位置以及错误是什么(

事实上,与回调、承诺和生成器函数相比,async/await旨在减少样板文件并使异步程序更易于编写。

  • 虽然 promise 是出于相同的目标创建的,但它们有一个额外的约束,即必须在现有的 JS 引擎中工作——所以它们的语法更复杂。使用 async/await 需要一个相对较新的 JS 引擎。如果您正在编写自己的 node.js 应用程序可能无关紧要,但库可能需要与较旧的 node.js 版本兼容(我不确定您是否可以在没有生成器支持的情况下将其转译以在旧浏览器中使用(。
  • 由于 async/await 是较新的,因此它没有经过优化。去年进行的比较报告称,Bluebird promise(实现承诺简化版本的JS库(在某个基准测试中优于async/await。(当然,当您的用例发出一些网络请求时,这可能无关紧要。
  • 您可能仍然需要承诺并行执行多个异步操作(编辑:如果您需要它们的结果(

虽然async/await可能是清理异步逻辑的好方法,但值得指出的是,promise 逻辑可以显着清理,以至于与 async/await 替代方案非常相似:

const fs = require("fs");
const util = require("util")
//Could also use the experimental "fs/promise" api from node v10
const promisifiedReadFile = util.promisify(fs.readFile);
const readFile = (fileName) => promisifiedReadFile(fileName, 'utf8');
function chainReadJson(fileName, callback) {
return readFile(fileName)
.then(json => JSON.parse(json))
.then(result => callback(null, result))
.catch(e => {
console.log("Error reading or parsing file", e.message);
callback(e)
});
}

这里唯一的功能区别是所有错误日志记录都发生在链的末端的一个地方。

可以保留readFile和JSON.parse的拆分日志记录,但不可否认的是,这有点棘手。 您通常希望在处理错误后重新引发错误,以便跳过下游.then处理程序:但是,如果您再次引发错误,下游.catch处理程序将再次捕获它,如果您找不到过滤掉它的方法,这将导致重复日志记录。

这是可行的,但它有点痛苦,所以我把它排除在上面的代码之外。

最新更新