介紹 Node.js 未來兩處很不錯的新特性
一、Promise 化的 fs API
就在幾天前 Node.js 主干合入了一個巨大的 PR:
fs: add promises API by jasnell · Pull Request #18297 · nodejs/node
這個 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/node
在過去,我們使用 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
}
})()
這樣就減少了很多不必要的函數嵌套,并且讓代碼看起來更“同步”。