?Briella 2017-11-10 12:47 采纳率: 0%
浏览 53

异步功能与等待

I'm coming from a PHP background and I'm trying to learn NodeJS.

I know that everything in Node is async but I've found that i've been using the async / await combo quite a lot in my code and I wanted to make sure I wasn't doing something stupid.

The reason for it is that I have a lot of situations where I need the result of something before continuing (for example for a small ajax request). This small ajax request has no other purpose other than to do the set of things that I want it to and in the order that I specify so even if I do things the "async way" and write it using a callback i'm still having to wait for things to finish in the right order.

Right now whenever I find myself in this situation I just use await to wait for the result:

ie:

var result = await this.doSomething(data);

Opposed to using a callback

this.doSomething(data, function(callback) {
  // code
  callback();
});

To me the first example looks cleaner than the second one which is why I've been opting for that. But I'm worried that I might be missing something fundamental here. But in a situation where there is nothing else to process below the async call and the only way for things to progress is for it to follow a syncronous style, is there anything wrong with using the first style over the second?

  • 写回答

1条回答 默认 最新

  • weixin_33717117 2017-11-10 12:52
    关注

    But I'm worried that I might be missing something fundamental here.

    Nope, you're not, that's exactly what you want to do, assuming this.doSomething(data) is asynchronous (and if it's an ajax call, one hopes it is async) and that it returns a promise (which all functions defined with the async keyword do implicitly). (If it's not asynchronous, you don't need the await, although it's allowed.)

    You're probably being a bit confused (understandably) by the fact that things are going through a transition. Until recently, the overwhelming convention in Node APIs (the built-in ones and ones provided by third-party modules) was to use the "Node callback" pattern, which is that a function that will do asynchronous work expects its last argument to be a callback, which it will call with a first argument indicating success/failure (null = success, anything else is an error object) with subsequent arguments providing the result. (Your second example assumes doSomething is one of these, instead of being a function that returns a promise.)

    Example: fs.readFile, which you use like this:

    fs.readFile("/some/file", "utf-8", function(err, data) {
        if (err) {
            // ...handle the fact an error occurred..
            return;
        }
        // ...use the data...
    });
    

    This style quickly leads to callback hell, though, which is one of the reasons promises (aka "futures") were invented.

    But a lot of Node APIs still use the old pattern.

    If you need to use "Node callback"-pattern functions, you can use util.promisify to create promise-enabled versions of them. For instance, say you need to use fs.readFile, which uses the Node callback pattern. You can get a promise version like this:

    const readFilePromise = util.promisify(fs.readFile);
    

    ...and then use it with async/await syntax (or use the promise directly via then):

    const data = await readFilePromise("/some/file", "utf-8");
    

    There's also an npm module called promisify that can provide a promise-ified version of an entire API. (There's probably more than one.)

    Just because promises and async/await replace the old Node callback style in most cases doesn't mean callbacks don't still have a place: A Promise can only be settled once. They're for one-off things. So callbacks still have a place, such as with the on method of EventEmitters, like a readable stream:

    fs.createReadStream("/some/file", "utf-8")
        .on("data", chunk => {
            // ...do something with the chunk of data...
        })
        .on("end", () => {
            // ...do something with the fact the end of the stream was reached...
        });
    

    Since data will fire multiple times, it makes sense to use a callback for it; a promise wouldn't apply.

    Also note that you can only use await in an async function. Consequently, you may find yourself getting into the habit of a "main" module structure that looks something like this:

    // ...Setup (`require` calls, `import` once it's supported, etc.)...
    (async () => {
        // Code that can use `await `here...
    })().catch(err => {
        // Handle the fact an error/promise rejection occurred in the top level of your code
    });
    

    You can leave the catch off if you want your script to terminate on an unhandled error/rejection. (Node doesn't do that yet, but it will once unhandled rejection detection matures.)

    Alternately, if you want to use a promise-enabled function in a non-async function, just use then and catch:

    this.doSomething()
        .then(result => {
            // Use result
        })
        .catch(err => {
            // Handle error
        });
    

    Note: async/await is directly supported in Node 7.x and above. Be sure your target production environment supports Node 7.x or above if your'e going to use async/await. If not, you could transpile your code using something like Babel and then use the transpiled result on the older version of Node.

    评论

报告相同问题?

悬赏问题

  • ¥15 Coze智能助手搭建过程中的问题请教
  • ¥15 12864只亮屏 不显示汉字
  • ¥20 三极管1000倍放大电路
  • ¥15 vscode报错如何解决
  • ¥15 前端vue CryptoJS Aes CBC加密后端java解密
  • ¥15 python随机森林对两个excel表格读取,shap报错
  • ¥15 基于STM32心率血氧监测(OLED显示)相关代码运行成功后烧录成功OLED显示屏不显示的原因是什么
  • ¥100 X轴为分离变量(因子变量),如何控制X轴每个分类变量的长度。
  • ¥30 求给定范围的全体素数p的(p-2)/p的连乘积值
  • ¥15 VFP如何使用阿里TTS实现文字转语音?