2016年12月27日 星期二

[generator, write/read] 最簡單的方法 解決 nodejs 寫入/讀取的同步問題

How to use generator to handle async write/read sync issue
Jing, mqjing@gmail.com
GitHub: Download


Google doc: This Document.


一般 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.



References