How to use generator to handle async write/read sync issue
Jing, mqjing@gmail.com
GitHub: Download
一般 nodejs 中 write 是非同步的, 顧名思義, 就是當你執行寫入的工作時, 系統不會馬上執行寫入的工作. 而是會在系統安排的某一個時機, 才會執行寫入的工作.
因此, 如果當你執行寫入檔案的指令後, 想要立刻讀取檔案內容, 會因為系統尚未安排寫的動作 (非同步的關係), 導致讀取失敗 (內容為 0).
那麼, 我一定要在真正寫入後, 才讀取內容, 該怎麼做? 這是一個非同步 function 的同步問題.
你可以使用 async/wait 搭配 promise 優雅的解決這個問題. (參考這篇). 但缺點是, 你得使用 v8 的 night build 版, 因為目前 ES6 並不支援 async/wait 語法. async/wait 是屬於 ES7 的新語法.
那麼在現階段, 我要如何不要大費周章, 就輕易解決簡單的 write / read 的問題呢? 你可以使用 generator function 搭配 next.
邏輯是這樣的!
- Generator function 可以用來包住一堆需要同步化、有執行順序需求的非同步執行函式。
- 然後,你在一個個非同步函式完成工作後,在 callback function 內用 next() 控制 Generator 繼續執行,讓等待非同步函式完成的 Generator 能 function 繼續完成它的工作。
Generator 規則
- 放在 Generator function 裡面需要同步的 async function, 就使用 yield 來等待.
- 一開始, Generator function 裡面的工作是處於 pause 狀態
GitHub: Download
var myGenerator;
function main() {
myGenerator = MyGeneratorFunction();
var retObj = myGenerator.next(); // start to run the MyGeneratorFunction
console.log('myGenerator.next() = ', retObj);
retObj = myGenerator.next(); //
// console.log('myGenerator.next() = ', retObj);
}
// Generator Function includes codes requiring to sync
function* MyGeneratorFunction(){
yield doAsyncFn(); // Run doAsyncFn and then pause until next() was involded
yield doAyncFnThatDependsOnA(); // Run doAyncFnThatDependsOnA and then pause until next() was involded
}
// Async Function
function doAsyncFn(){
let fs = require('fs');
console.log('run doAsyncFn()');
strCode = "Hellow World\n";
fs.writeFile("out.txt", strCode, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
var retObj = myGenerator.next(); // <-------------- next="" resume="" span="" the="" to="">-------------->
console.log('myGenerator.next() = ', retObj);
});
}
// Any Function that depends on Async Function
function doAyncFnThatDependsOnA() {
let fs = require("fs");
fs.readFile('out.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("Asynchronous read: " + data.toString());
var retObj = myGenerator.next(); // <-------------- generato="" resume="" span="" the="">r -------------->
console.log('myGenerator.next() = ', retObj);
});
}
main();
|
E.g.