简体   繁体   中英

Is there any advantage in nodejs calling an async function followed by an await versus a synchronous function?

I recently saw this kind of code in an asynchronous function :

async function foo() {
    const readFile = util.promisify(fs.readFile);
    const data = await readFile(file, 'utf8');
    // .... other code
}

Is there any advantange of doing this over:

async function foo() {
    const data = readFileSync(file, 'utf8');
    // ... other code
}

?

In general I am interested in if there is any advantage over calling an asynchronous function followed by an immediate wait on the return, as opposed to calling the corresponding synchronous function without the wait.

And suppose this async function had already been wrapped say in a promise?

Note: some of the comments and answers refer to an earlier version of this code which was buggy and less clear about the intent.

The answer to your very valid question is that the synchronous methods will block the thread, whereas the async methods will allow other JavaScript to run while the operation takes place, giving your application more room to scale.

For example, if you wrote an http server and only have one request coming in per minute and never simultaneously, it wouldn't matter much what you do. The thread is being blocked for mere milliseconds and that work is unavoidable with respect to the request that is relying on it. However, if you have 100 requests per minute coming through, and maybe some other work being done on some cron schedule in the same JS app, then using the asynchronous methods would allow those requests to continue to come through your server code (JS) while the filesystem work is being done behind the scenes (in C++, I believe, but you'd have to google that part). When the thread is blocked by a synchronous function, then all of those requests and events pile up in the event queue waiting for the JS to handle them, even though the JS event loop probably isn't busy with anything directly. It's only waiting. That's not good, so take advantage of the asynchronous nature of single-threaded JS as much as possible.

With respect to error handling, the async versions of those functions have an error object (or null when successful) as the callback's first parameter, which is transferred to the .catch method when you promisify it. This allows for natural and built-in error handling. You will observe with the *Sync functions that there is no callback, and, if it errors, you will not receive that error in a helpful way (usually it crashes the app). Here are two examples to illustrate:

Unhelpful.js

const fs = require('fs')
const util = require('util')

const test = fs.readFileSync('./test.js') // spoiler alert: ./test.js doesn't exist

console.log('test:', test) // never runs, because the error thrown is not caught and the process exits :(

/*
Output:

fs.js:113
    throw err;
    ^

Error: ENOENT: no such file or directory, open './test.js'
    at Object.openSync (fs.js:434:3)
    at Object.readFileSync (fs.js:339:35)
    ...etc...
*/

Better.js

const fs = require('fs')
const util = require('util')
const readFile = util.promisify(fs.readFile)

;(async function () {
  // The catch handler actually returns the error object, so test will hold
  // the value/result of the readFile operation whether it succeeds or fails
  const test = await readFile('./test.js').catch(err => err instanceof Error ? err : new Error(err))

  console.log('test:', test)
  // helpful log, as a result:
  // test: { [Error: ENOENT: no such file or directory, open './test.js'] errno: -2, code: 'ENOENT', syscall: 'open', path: './test.js' }
})()

So now that I think I understand the situation, let me try to explain my confusion.

I had thought V8 or nodejs maintained a list of runnable threads even if only one was ever running at a given time. Also I assued that that async functions created a new thread. Thus if that thread was blocked, no problem, because some other runabble thread would be swapped in.

From what people have posted, I now am given to believe that there is only one thread (at least visible to the programmer), so blocking anywhere (whether or not there are coroutines/async functions) blocks everywhere .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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