首页 文章

Javascript:承诺链与异步/等待?

提问于
浏览
11

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

在示例代码中,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 chain为ChainReadJson函数编写代码时,我很难控制执行结果和错误 .
但是,当使用async / await编写AwaitReadJson函数的代码时,这些困难大多消失了 .

我是否正确理解了异步/等待的好处?与promise链相比,async / await有哪些缺点?

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

2 回答

  • 9

    实际上,与回调,承诺和生成器函数相比, async/await 减少了样板并使异步程序更容易编写 .

    • 虽然promises是以相同的目标创建的,但它们还有必须在现有JS引擎中工作的附加约束 - 因此它们的语法更复杂 . Using async/await requires a relatively new JS engine. 如果您不确定是否可以将其转换为在没有生成器支持的旧版浏览器中使用,则可能无关紧要 .

    • 由于async / await较新, it's not as optimized . 在去年进行的比较reports Bluebird承诺(实施简化版Promises的JS库)在某个基准测试中优于async / await . (当您的用例发出一些网络请求时,这可能无关紧要 . )

    • 您可能仍然need promises to execute several asynchronous actions in parallel(编辑:如果您需要他们的结果)

  • 3

    虽然 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 处理程序将再次捕获该错误,这将导致重复记录,如果您没有找不到一种方法来过滤掉它 .

    它是可行的,但它有点痛苦,所以我把它从上面的代码中删除了 .

相关问题