异步函数和毁掉函数是 JS 单线程并行模型的核心。
在 JS 中,需要区分 I/O 操作
和 CPU 密集型操作
。针对 I/O 来说,例如网络请求和文件操作,需要程序等待数据准备好后再进行下一步操作,与此同时,程序可以执行其他的代码,这并不会对程序产生阻塞。
而对于 CPU 密集型的操作来说,它会造成线程的阻塞。
- 对于 I/O 操作来说,我们需要使用
promise
,events
和callback
来对请求做划分(schedule) - 对于 CPU 密集型的操作来说,它会不可避免的阻塞程序的执行,这时候可以使用
worker threads/web workers
来执行
在使用 ascyn/await
的时候需要注意,未经处理的 promise
将会造成很大的内存使用。
注意事项
- 不要使用
return await
语句
return await
的问题
通常在函数中, return
语句表明了函数的结束,并且会从当前调用栈中弹出。对于 async
函数来讲,会将一个值用一个已解决(resolved)的 promise
进行包裹,然后再进行返回。
与此同时, await
语句标明 async
函数暂停执行,直到一个给定的 promise 解决之后。将 return
和 await
进行结合之后会导致多余的对已经解决的 promise 进行多余的包装和解包装的操作。
通常来说,在 async
函数中最后的 promise 应该被直接返回。
async function saveJSON(output) {
const response = await fetch('https://api.github.com')
const json = await response.json()
const text = JSON.stringify(json)
return fs.readFile(output, text)
}
避免对 async
函数的滥用:
import { promises as fs } from 'fs';
// This is a not-so-efficient wrapper for the native file reader.
async function readFile(filename) {
const contents = await fs.readFile(filename, { encoding: 'utf8' });
return contents;
}
// Preferred
// This optimization avoids the `async` wrapper overhead.
function readFile(filename) {
return fs.readFile(filename, { encoding: 'utf8' });
}