简体   繁体   English

Javascript:promise 链 vs. async/await?

[英]Javascript : promise chain vs. async/await?

I am learning about Javascript Promise and async / await .我正在学习 Javascript Promiseasync / await The sample code below asynchronously reads and parses a JSON file in node.js ( my node.js version is v10.0.0 ).下面的示例代码异步读取并解析 node.js 中的 JSON 文件(我的 node.js 版本是 v10.0.0 )。

In the sample code, ChainReadJson function and AwaitReadJson function are doing the same thing, reading and parsing a JSON file.在示例代码中,ChainReadJson 函数和 AwaitReadJson 函数在做同样的事情,读取和解析 JSON 文件。 The difference is that ChainReadJson function uses a promise chain, while AwaitReadJson function uses async/await.不同之处在于 ChainReadJson 函数使用了一个 promise 链,而 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);
}

When writing the code for ChainReadJson function using promise chain, I had difficulties controlling execution results and errors.在使用承诺链为 ChainReadJson 函数编写代码时,我很难控制执行结果和错误。 However, when writing the code for AwaitReadJson function using async/await, those difficulties are mostly disappeared.但是,当使用 async/await 编写 AwaitReadJson 函数的代码时,这些困难大多消失了。

Do I correctly understand the benefits of async/await?我是否正确理解 async/await 的好处? What are the disadvantages of async/await compared to promise chain?与承诺链相比,async/await 的缺点是什么?

(The sample code is a modified version of the code in this answer . The original code uses promise chain only, and is written to know exactly where in the chain the error occurred and what is the error) (示例代码是此答案中代码的修改版本。原始代码仅使用承诺链,并编写以确切了解错误发生在链中的哪个位置以及错误是什么)

Indeed, async/await were designed to reduce boilerplate and make asynchronous programs easier to write, compared to callbacks, promises, and generator functions.实际上,与回调、promise 和生成器函数相比, async/await旨在减少样板代码并使异步程序更易于编写。

  • While promises were created with the same goal, they had the additional constraint of having to work in the existing JS engines -- so their syntax is more complicated.虽然 promises 是为相同的目标创建的,但它们具有必须在现有 JS 引擎中工作的额外限制——因此它们的语法更加复杂。 Using async/await requires a relatively new JS engine .使用 async/await 需要一个相对较新的 JS 引擎 It might not matter if you're writing a node.js app of your own, but a library might need to be compatible with older node.js versions (and I'm not sure if you can transpile it for use in older browsers without generator support).如果您正在编写自己的 node.js 应用程序可能无关紧要,但是库可能需要与旧的 node.js 版本兼容(我不确定您是否可以在没有发电机支持)。
  • Since async/await is newer, it's not as optimized .由于 async/await 较新,因此没有优化 A comparison made in the last year reports Bluebird promises (a JS library implementing simplified version of promises) outperforming async/await in a certain benchmark.去年的一项比较报告称, Bluebird promises(一个实现简化版本 promise 的 JS 库)在某个基准测试中的表现优于 async/await。 (Of course this may not matter when your use-case is making a few network requests.) (当然,当您的用例发出一些网络请求时,这可能无关紧要。)
  • You might still need promises to execute several asynchronous actions in parallel (edit: if you need their results)您可能仍然需要承诺并行执行多个异步操作(编辑:如果您需要它们的结果)

While async/await can be a nice way to cleanup asynchronous logic, it's worth pointing out that the promise logic can be cleaned up significantly, to the point of being very similar to the async/await alternative:虽然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)
        });
}

The only functional difference here is that all the error logging occurs at one place, at the end of the chain.这里唯一的功能区别是所有的错误日志都发生在一个地方,在链的末端。

It's possible to preserve the split logging for the readFile and the JSON.parse, but that is admittedly a bit trickier.可以保留 readFile 和 JSON.parse 的拆分日志记录,但这无疑有点棘手。 You generally want to re-throw errors after handling them, so that the downstream .then handlers are skipped: but if you throw the error again, it'll be caught again by the downstream .catch handlers, which will cause duplicate logging, if you don't find a way to filter it out.通常你想重新抛出错误处理它们后,使下游.then处理程序跳过:但如果你再扔的错误,它会再次被抓住下游.catch处理程序,这将导致重复记录,如果你找不到过滤掉它的方法。

It's doable, but it's a bit of a pain, so I left it out of the above code.这是可行的,但有点痛苦,所以我把它从上面的代码中去掉了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM