For the implementation of a minimalist version of Co, the code is as follows (https://gist.github.com/iwillwen/8488050)
functionCo (generator) {return function(FN) {varGen =generator (); functionNext (err, result) {if(err) {returnfn (ERR); } varStep =Gen.next (Result); if(!step.done) {step.value (next); } Else{fn (NULL, Step.value); }} next (); }}
To understand this code, take a look at an example
varCO = require ('./co '));//wrap the function to thunkfunctionreadFile (filename) {return function(callback) {require (' FS '). ReadFile (filename, ' UTF8 '), callback); };} Co (function* () { varFile1 = Yield readFile ('./file/a.txt ')); varFile2 = Yield readFile ('./file/b.txt ')); Console.log (FILE1); Console.log (file2); return' Done ';}) (function(err, result) {Console.log (Result)});
Now let's do the sequence to illustrate
- The first is the following sections
Co (function * () { var file1 = Yield readFile ('./file/a.txt '); var file2 = Yield readFile ('./file/b.txt '); Console.log (file1); Console.log (file2); return ' Done '; })
This part of the code executes the CO function and passes function* () as the parameter generator, that is, the whole part becomes
function(FN) {varGen =generator (); functionNext (err, result) {if(err) {returnfn (ERR); } varStep =Gen.next (Result); if(!step.done) {step.value (next); } Else{fn (NULL, Step.value); }} next (); }(function(err, result) {Console.log (Result)})
This part performs this function and puts
function (err, result) {
Console.log (Result)}
The arguments that are passed as FN.
2. During execution, ' Var gen ' is the ' function ' () ' section, following the declaration of the function ' next () ', followed by the ' Next () ' function, at which time ' err ' and ' result ' are null.
3. ' Err ' is null, so ' if (err) ' is not executed, execute ' var ' step = Gen.next (Result), ' because ' result ' is empty here, so
var step = Gen.next (result) step.value=readfile ('./file/a.txt ')=function( Callback) { require (' FS '). ReadFile ('./file/a.txt ', ' UTF8 ', callback); };
4. ' Step.done ' is ' false ', execute ' step.value (next); ', execute
function (callback) { require (' FS '). ReadFile ('./file/a.txt ', ' UTF8 ', callback);};
function, and ' next ' as ' callback ' incoming. The ' readFile ' parameter of the incoming callback function is ' err ' and ' data ', so after reading the file, the contents of ' err ' and the A file (as the actual argument of result) are passed into the ' next ' function and executed.
5. Similar to 2,3, execute ' var step = Gen.next ', this step because the value of result is the content of a file, so ' file1 ' is assigned the content of a file (next method can take a parameter, The parameter is treated as the return value of the previous yield statement. )。 Similar to 4, the contents of Err and B file (as the actual argument of result) are passed into the ' next ' function and executed.
6. When re-executing to ' var step = Gen.next ', ' file2 ' is given the content of file B, because ' generator ' does not have ' yield ', then executes to ' return ', ' step.value= ' Done ', ' step.done=true ', where the function stops from the last yield statement and executes to the return statement (executed to the end of the function if there is no return statement). The Value property of the object returned by the next method is the value of the expression immediately following the return statement (if there is no return statement, the Value property is undefined) and the Done property evaluates to true, indicating that the traversal has ended. )
7. Execute ' fn (null, step.value); '
function (Err, ' done ') { console.log (' done ');} ();
8. As a result, the code executes
Content in A.txt
Content in B.txt
Done
Understanding the Co execution logic