【问题标题】:Javascript : promise chain vs. async/await?Javascript:承诺链与异步/等待?
【发布时间】:2018-10-17 19:06:52
【问题描述】:

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

在示例代码中,ChainReadJson 函数和 AwaitReadJson 函数做同样的事情,读取和解析 JSON 文件。区别在于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);
}

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

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

(示例代码是the code in this answer的修改版本。原始代码仅使用promise链,编写是为了准确知道错误发生在链中的哪个位置以及错误是什么)

【问题讨论】:

  • 你对 Promise 链和 async/await 都很了解。 . .其余的是本网站不擅长的意见。忽略我的拙见,async/await 并没有任何缺点,除了它不受任何地方的支持。
  • 您在使用 Promise 链时遇到了哪些错误?你是如何使用 ChainedPromiseJSON 的? 2个代码不一样,在promise链中,如果JSON.parse的返回不是undefined,你只执行回调,而在你的等待情况下,你总是执行回调。
  • @generalhenry:感谢您的意见。
  • @cowbert :示例代码工作正常。如果您阅读this answer,您可以更轻松地理解示例代码。
  • 你为什么要创建 2 个单独的问题。无论如何,如果上一步(第一个then 导致错误,那么它会在第二个then 中触发错误回调)。检查res !== undefined 只会在JSON.parse 返回 undefined 时执行,这永远不会发生,它会抛出一个 SyntaxError。

标签: javascript node.js async-await es6-promise


【解决方案1】:

确实,async/awaitdesigned,与回调、promise 和生成器函数相比,它可以减少样板文件并使异步程序更易于编写。

  • 虽然 Promise 的创建目的相同,但它们还有一个额外的限制,即必须在现有的 JS 引擎中工作——因此它们的语法更加复杂。 使用 async/await 需要 relatively new JS engine 如果您正在编写自己的 node.js 应用程序可能并不重要,但库可能需要与较旧的 node.js 版本兼容(而且我不确定您是否可以将其转换为在不支持生成器的旧浏览器中使用)。
  • 由于 async/await 较新,没有优化。去年进行的比较reportsBluebird Promise(一个实现 Promise 简化版本的 JS 库)在某个基准测试中优于 async/await。 (当然,当您的用例发出一些网络请求时,这可能无关紧要。)
  • 你可能仍然need promises to execute several asynchronous actions in parallel(编辑:如果你需要他们的结果)

【讨论】:

  • 感谢您的回答并纠正我的问题。这对我有很大的帮助。我也同意你的观点,这是 async/await 的一个缺点:“使用 async/await 需要一个相对较新的 JS 引擎”
  • 关于这个:“仍然需要承诺并行执行几个异步操作”......当我同时执行几个异步/等待函数时,它们只是并行工作。我认为这是一个自然的结果,因为 async/await 函数是在 Promise 基础上运行的。我说的对吗?
  • @pdh0710 如果“执行”是指在没有await 的情况下调用异步函数,那么可以。但是由于您通常关心异步操作的结果(如果只是为了错误处理),您将不得不处理返回的承诺。
  • 我用 await 执行了几个异步函数。顺便问一下,没有await的async函数有用吗?
  • @pdh0710 如果你的意思是await f1();await f2();,那么不,它们并行运行,check out this example from MDN,它也说明了为什么你会在没有@987654329 的情况下调用异步函数@。我现在得走了,所以如果您还有其他问题,请尝试发布另一个问题,或者找个实时聊天——stackoverflow cmets 是一个糟糕的沟通工具。
【解决方案2】:

虽然async/await 可能是清理异步逻辑的好方法,但值得指出的是,可以显着清理承诺逻辑,以至于与 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处理程序再次捕获,这将导致重复记录,如果你没有找到过滤掉它的方法。

这是可行的,但是有点麻烦,所以我把它从上面的代码中省略了。

【讨论】:

    猜你喜欢
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    • 2021-11-09
    • 2021-10-03
    • 1970-01-01
    • 2021-10-07
    相关资源
    最近更新 更多