reference:
- https://www.cnblogs.com/chenjinxinlove/p/8467774.html
- https://juejin.im/post/5b54ca8ef265da0f7e628b6f
- https://juejin.im/post/5a30193051882503dc53af3c#heading-13
- https://juejin.im/post/5bcf3e3f6fb9a05cd53b3e3d#heading-11
1. 深入理解異步操作
在“認(rèn)識generator”這篇文章中,我更多地是從迭代器的角度去看generator,我們現(xiàn)在從異步操作的角度來看待generator:
function* gererator(){
//do some stuff
yield value1;
//do some stuff;
yield value2;
}
執(zhí)行權(quán)一直calling code和generator函數(shù)兩個地方輪換,兩段代碼的數(shù)據(jù)交流可以通過yield和.next(data)進(jìn)行交換。
generator異步讀取文件的實例:
var fs=require('fs');
var readfile=function(filename){
return new Promise((resolve,reject=>{
fs.readFile(filename, (error,data)=>{
if(error) reject(new Error('whoops');
resolve(data);
});
});
}
//generator
var gen=function* (){
var file1=yield readfile('./data1.json');
var file2= yield readfile('./data2.json');
console.log('done');
}
//calling code
var generator=gen();
generator.next().value.then(data=>{
generator.next(data).value.then((data)=>{
generator.next(data);
}
);
});
在外層的calling code部分,我們可以用自動執(zhí)行器,來讓generator函數(shù)執(zhí)行,比如我們可以引入模塊co來完成上述calling code的操作。
也可以自己寫一個自動執(zhí)行器:
function run(generator){
var g=generator();
function next(data){
var result=g.next(data);
if(result.done){
console.log(result.value);
}else{
result.value.then(function(data){
next(data);
});
}
}
next();
}
事實上,上述代碼如果async和await的語法來寫,就會變得非常簡潔。
async function loadFile(){
var file1=await readfile('./data1.json');
var file2=await readfile('/data2.json');
console.log('done');
}
2. async函數(shù)的實現(xiàn)原理, 就是將Generator 函數(shù)和自動執(zhí)行器, 包裝在一個函數(shù)里。
function getName(name){
return new Promise((resolve)=>{
setTimeout(resolve(name),1000);
});
}
function* gen(){
let data1=yield getName('nancy');
let data2=yield getName('bill');
return [data1,data2];
}
function run(generator){
return new Promise(resolve=>{
var g=generator();
var output;
function next(data){
var result=g.next(data);
if(result.done){
output=result.value;
resolve(output);
}else{
result.value.then(function(data){
next(data);
});
}
}
next();
});
}
run(gen).then(console.log); //output ['nancy','bill'].
//example:
// var fs=require('fs');
function getName(name)
{
return new Promise(resolve=>{
setTimeout(resolve(name),1000);
});
}
async function readfile(name1,name2){
let data1=await getName(`hello, ${name1}`);
let data2=await getName(`hello, ${name2}`);
return [data1,data2];
}
// now use promise and generator.
function* generator(name1,name2){
let data1=yield getName(`hello, ${name1}`);
let data2=yield getName(`hello, ${name2}`);
return [data1,data2];
}
function wrapper(gen){
return function(...args){
return new Promise(resolve=>{
var g=gen(...args);
function next(data){
var result=g.next(data);
if(result.done) resolve(result.value)
else{
result.value.then(data=>{
next(data);
});
}
}
next();
});
}
}
var readfile_gen=wrapper(generator);
readfile('jason','gisele').then(console.log);
readfile_gen('jason','gisele').then(console.log);
包裝函數(shù):
const wrapAsync=function(generatorFn){
return function(...args){
return new Promise(resolve=>{
var g=generatorFn(...args);
function next(data){
var result=g.next(data);
if(result.done) resolve(result.value);
else{
result.value.then(data=>{
next(data);
});
}
}
next();
});
}
}