一、Promise 化的 fs API
就在几天前 Node.js 主干合入了一个巨大的 PR:
fs: add promises API by jasnell · Pull Request #18297 · nodejs/nodegithub.com这个 PR 实验性地加入了 Promise 化的 fs API。虽然现在我们可以使用 util.promisify
来简单地封装 fs 这一套 API,但这只是“封装”。从 Node.js 内核层面上支持 Promise 会有更大的性能优势。
以后我们可以这样优雅的读取文件:
const { readFile } = require('fs').promises
async function readAndPrint(filename) {
console.log(await readFile(filename))
}
readAndPrint('file')
错误处理也可以直接使用 try...catch
了,而不是用 Promise.catch
:
const { readFile } = require('fs').promises
try {
await readFile('file')
} catch(e) {
console.log(e)
}
二、支持 Async Iterators 的 stream API
Async Iterators 目前已经进入 stage-3 阶段,未来将会进入语言标准,V8 目前已经支持这个语言特性。先简单介绍一下 Async Iterators(异步迭代器)是什么。
ES6 的 Generator 函数大部分人应该都或多或少知道一些:
function* idMaker() {
var index = 0;
while(true)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...
简单地说,如果我们在 Generator 每次 yield 出的都是一个 Promise,那么它就成为了一个 Async Iterators:
function* asyncIdMaker() {
var index = 0;
while(true)
yield Promise.resolve(index++);
}
(关于 Generator 和 Iterator 的关系,可以参考这里)
针对 Async Iterators,可以使用专门的 for await
语法来操作:
for await (const id of asyncIdMaker()) {
console.log(id)
}
Node.js 的 stream API 在今年年初也实验性地加入了这个特性:
stream: added experimental support for for-await by mcollina · Pull Request #17755 · nodejs/nodegithub.com在过去,我们使用 stream API 时一般都会写出类似这样的代码:
// 创建一个 stream
var myReadStream = fs.createReadStream('filename', 'utf-8')
// 响应 data 事件
myReadStream.on('data', function(chunk) {
console.log(chunk);
// 处理 chunk
})
这种基于事件回调的实现其实是不太优雅的,逻辑只要稍微复杂一些就很容易写出嵌套层次很深的代码。
现在我们可以使用 Async Iterators 这个新特性来处理:
// 创建一个 stream
var myReadStream = fs.createReadStream('filename', 'utf-8');
(async () => {
for await (const chunk of myReadStream) {
console.log(chunk);
// 处理 chunk
}
})()
这样就减少了很多不必要的函数嵌套,并且让代码看起来更“同步”。