Original address: http://www.moye.me/2014/11/10/ecmascript-6-generator/
Introduction
Old listen to people say koa Dafa good, these two days I also rushed to fashion: with N to install node 0.11.12, under a KOA Open Harmony mode test water. In the education of a series of documents and posts, it is probably recognized that:
- KOA is a new generation of web frameworks dominated by TJ God
- KOA Middleware is based on the ES6 generator function * Form
- KOA Core Process Library is co, it can solve pyramid of doom problem very well
Before I contacted node. js, I was already aware of what the generator was about because of the experience of Python programming. What I'm really interested in is how it was used to optimize the callback nesting.
"Why are you so fucking?"
In the KOA framework why is there such a piece in the article (Fragment 1):
varFS = require (' FS ');varApp = require (' KOA ')();varReadFile =function(dir) {return function(FN) {fs.readfile (dir, FN); }}app.use (function* () { vararr = yield [' 1.txt ', ' 2.txt ', ' 3.txt '].map (function(path) {returnreadFile (path); }); This. BODY = Arr.join (', ');}) App.listen (8000);
This code is a good example of how KOA uses the Generator function (function* (), the function's constructor.name = = = ' Generatorfunction ') to serialize the asynchronous callback, and its execution flow:
function*(){...}
Was made as a generator function push into the KOA middleware queue
- KOA uses the CO framework to execute calls to the generator function, and the generator function does not immediately execute the function body, but instead generates the generator (generator) instance--and the generator can be treated as an instance of the iterator protocol, and each time the next () of the iterator is called, it will return a
{ value: obj, done:true/false }
Object: Value is the execution result value, done indicates whether the iteration is complete
- The next () method that invokes the generator instance launches the execution flow inside the function body until yield is suspended, and next next () will give yield the resulting value of execution and suspend at the next yield occurrence; it can be understood that yield always returns to the previous next () result value, if Next () has parameters, yield returns this parameter value (async callback has the opportunity to inject the execution result)
- Observing the code snippet above, we notice that ReadFile's callback handler is not provided in the FN code, so what does KOA or co do with the callback function? In Koa (0.13.0), the following fragment (fragment 2) can be seen in the Co source code (LINE:84):
//NormalizeRet.value =Tothunk (Ret.value, CTX);//Runif(' function ' = =typeofret.value) {varcalled =false; Try{ret.value.call (CTX,function(){ if(called)return; Called=true; Next.apply (CTX, arguments); }); } Catch(e) {setimmediate (function(){ if(called)return; Called=true; Next (e); }); } return;}
- the tothunk is converted into a standard function based on the expression returned by yield (fragment 3):
functiontothunk (obj, ctx) {if(isgeneratorfunction (obj)) {returnCo (Obj.call (CTX)); } if(Isgenerator (obj)) {returnCo (obj); } if(ispromise (obj)) {returnpromisetothunk (obj); } if(' function ' = =typeofobj) { returnobj; } if(IsObject (obj) | |Array.isarray (obj)) { returnObjecttothunk.call (CTX, obj); } returnobj;}
- In fragment 1, the generator function first returns a generator, and then the yield binding map returns three function objects, the function returned by the higher-order functions ReadFile:
function (FN) { fs.readfile (dir, fn);}
- Fragment 2 calls the function and provides a callback function based on the type returned by the Fragment 3: The arguments is
next.apply(ctx, arguments);
passed smartly. As mentioned earlier, next () if the parameter is provided, the result value of yield is this parameter, and the callback result is thus.
Who the hell is that?
If crossing after reading the above paragraphs are not dizzy, it is your most cock:)-My ability to express is really not enough to clear the framework of the mystery, but in my opinion, the real dick is the ES6 generator mechanism itself.
Temporarily lay down the Co framework, transforming the piece 1 slightly (fragment 4):
varFS = require (' FS ');varPath = require (' path '); varReadFile =function(dir) {return function(FN) {fs.readfile (dir, {encoding:' UTF8 ', flag: ' R '}, FN); };}; function*readfilegeneratorfunction (Path, CB) {Console.log (yield readFile (path) (CB));} varReadfileiterator = readfilegeneratorfunction (' testdate.js '), callback);functioncallback (err, data) {readfileiterator.next (data);} Readfileiterator.next ();
The intention is obvious:
- This readfilegeneratorfunction is a generator function that executes it to return a generator (iterator)
- function returned by higher order functions, with callback specified when generator function executes
- Next triggers execution
- When the callback is complete, next (data) carries the result value to trigger yield
The problem is also obvious that the business code (yield in generatorfunction) needs to be placed before the process Control (callback), which is unscientific. Abstract, you can provide an execution function for a generator function:
function Run (generatorfunction) { var generatoritr = generatorfunction (callback); function callback (err, data) { if(err) console.log (err); Generatoritr.next (data); } Generatoritr.next ();}
Test it:
Run (function* Rfgenfunc (CB) { console.log (' first '); Console.log (Yield readFile (' 1.txt ') (CB)); Console.log (' second '); Console.log (Yield readFile (' 2.txt ') (CB));});
Execution Result:
Summary
This article only gives a brief description of the next () Application of generator (in fact it has more content such as: Throw/send/close). As for the generator features, it is still in the draft ECMAScript 6 specification, as stated in MDN: Use caution:)
More articles please visit my blog new address: http://www.moye.me/
[node. js] ECMAScript 6 Generator and KOA small analysis