我最近在异步函数中看到了这类代码 :
async function foo() {
const readFile = util.promisify(fs.readFile);
const data = await readFile(file, 'utf8');
// .... other code
}
是否有这样做的优势:
async function foo() {
const data = readFileSync(file, 'utf8');
// ... other code
}
?
总的来说,我感兴趣的是与调用异步函数然后在返回时立即等待相比,是否有优势,而不是调用相应的同步函数而无需等待。
并且假设这个异步功能已经被包装在一个诺言中了?
注意:一些注释和答案引用的是此代码的早期版本,该版本存在错误,并且意图不明确。
答案 0 :(得分:3)
非常有效的问题的答案是:同步方法将阻塞线程,而异步方法将允许其他JavaScript在操作发生时运行,从而为您的应用程序提供更大的扩展空间。
例如,如果您编写了一个http服务器,并且每分钟仅收到一个请求,并且从未同时发出请求,那么您执行什么操作都没关系。线程仅被阻塞几毫秒,对于依赖它的请求,工作是不可避免的。但是,如果您每分钟要处理100个请求,并且可能在同一个JS应用程序中按某些cron计划进行了其他工作,则使用异步方法将允许这些请求继续通过服务器代码(JS)进行处理,文件系统的工作正在幕后完成(我相信,在C ++中,但是您必须用Google搜索这一部分)。当线程被同步函数阻塞时,所有这些请求和事件都会堆积在事件队列中,等待JS处理它们,即使JS事件循环可能并不直接忙于任何事情。 / em>这只是在等待。那不是很好,因此请尽可能利用单线程JS的异步特性。
关于错误处理,这些函数的异步版本具有一个错误对象(或成功时为null
)作为回调的第一个参数,当您对其进行合理化时,该对象将传递给.catch
方法。这允许自然的和内置的错误处理。您将使用*Sync
函数观察到没有回调,并且如果发生错误,您将不会以有用的方式收到该错误(通常会使应用程序崩溃)。这里有两个例子来说明:
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' }
})()
答案 1 :(得分:0)
现在,我认为我已经了解了情况,让我尝试解释一下我的困惑。
我曾以为V8或nodejs维护了一组可运行线程,即使在给定时间只运行了一个。我也保证异步功能创建了一个新线程。因此,如果该线程被阻止,就没有问题,因为其他一些runabble线程将被交换。
根据人们发布的内容,现在我相信只有一个线程(至少对程序员可见),因此可以在任意位置阻塞 (无论是否有协程/异步函数) )阻止无处不在。