ES6 Generator使用

// generator介绍:
function* hello() {
console.log("hello world")
}
hello();//没有执行编程

// 直接调用hello不能像普通函数同样打印输出。promise

function* hello() {
console.log("hello world")
}
var h = hello();//仅仅建立了函数句柄,并无实际执行,须要进一步调用next()
h.next();//打印出了“hello world”多线程

function* hello() {
yield "hello";
yield "world";
return;
}异步

var h = hello();
h.next();//{value:'hello',done: false}
h.next();//{value: 'world', done: false}
h.next();//{value: undefined, done: true}异步编程

// 分析:上面引入了yield关键字:函数

// (1)建立了h对象,指向hello的句柄,线程

// (2)第一次调用next(),执行到"yield hello",暂缓执行,并返回了"hello"指针

// (3)第二次调用next(),继续上一次的执行,执行到"yield world",暂缓执行,并返回了"world"。对象

// (4)第三次调用next(),直接执行return,并返回done:true,代表结束。ip

// 通过上面的分析,yield实际就是暂缓执行的标示,每执行一次next(),至关于指针移动到下一个yield位置。

// 总结一下,Generator函数是ES6提供的一种异步编程解决方案。经过yield标识位和next()方法调用,实现函数的分段执行。

function* gen(x, y) {
let z = yield x + y;
let res = yield z * 5;
return res;
}

var g = gen(5,6);
console.log(g.next());//{value: 11, done: false};
console.log(g.next());//{value: NAN, done:false};
console.log(g.next());//{value: undefined, done: true}

// 分析:

// (1)建立了g对象,指向gen的句柄,并传入参数x=5,y=6
// (2)第一次调用next(),执行yield x+y, value值是11,后面尚未return,也没有到最后的yield,因此没退出
// (3)第二次调用next(),执行yield z*5, 为何输出是 NAN并非预想的55呢?由于将yield表达式的结果赋值给z以后,进行下一次next(),z的值并无保存。
// (4)第三次调用next(),遇到return,执行结束done:false

// 分析(3),z的值没有保存,可是怎么才能达到预期的55呢?改为下面的程序段

function* gen(x, y) {
let z = yield x + y;
let res = yield z * 5;
return res;
}

var g = gen(5,6);
console.log(g.next());//{value: 11, done: false};
console.log(g.next(11));//{value: NAN, done:false};
console.log(g.next());//{value: undefined, done: true}

// 再执行第二次next()调用时,next的参数11能够做为yield中,参数11是上一次yield表达式的结果,也就是let z=yield x+y 变成了 let z=11;因此输出了正确的结果

// 咱们不能每次都把计算好的结果写到参数中,因此,修改程序段以下:

function* gen(x, y) {
let z = yield x + y;
let res = yield z * 5;
return res;
}

var g = gen(5,6);
let i = g.next();//i: {value: 11, done: false};
console.log(g.next(i.value()));//{value: NAN, done:false};
console.log(g.next());//{value: undefined, done: true}

// 最终执行第二次next()调用时,value值是预期的55。

// 总结:next()函数的参数做为上一个yield表达式的结果。

function *gen() {
yield 1;
yield 2;
yield 3;
}

let g = gen();
g.next();//{value: 1, done: false}
g.next();//{value: 2, done: false}
g.return();//遇到return()函数,generat函数遍历结束,{value: undifined, done: true},yield 3表达式并无执行

function *gen() {
yield 1;
yield 2;
yield 3;
}

let g = gen();
g.next();//{value: 1, done: false}
g.next();//{value: 2, done: false}
g.return(5);//遇到return()函数,generator函数遍历结束,其参数5做为结果的value值{value: 5, done: true},yield 3表达式并无执行

// yield表达式是generator函数暂缓执行的标志,只能配合generator函数使用,用在普通函数中会报错。

function gen(x,y){
yield 1;
yield 2;
yield 3;
}//Uncaught SyntaxError: Unexpected number

// yield*表达式的用法:

function *foo() {
yield 'a';
yield 'b';
}

function bar() {
yield 1;
yield 2;
yield
foo();
yield 3;
}

var b = bar();

console.log(b.next());//{value: 1, done: false}
console.log(b.next());//{value: 2, done: false}
console.log(b.next());//{value: "a", done: false}
console.log(b.next());//{value: "b", done: false}
console.log(b.next());//{value: 3, done: false}
console.log(b.next());//{value: undefined, done: true}

// generator函数的应用:

// generator能够模拟多线程之间的协做。
// 好比说A,B两个线程根据实际逻辑控制共同完成某个任务,A运行一段时间后,暂缓执行,交由B运行,B运行一段时间后,再交回A运行,直到运行任务完成。
// 对于JavaScript单线程来讲,咱们能够理解为函数间的协做,由多个函数间相互配合完成某个任务。

// Generator函数是ES6提供的一种异步编程解决方案,解决了异步编程的两大问题:
// 回调地狱和异步控流
// 回调地狱与promise有关,不作介绍了

// 异步控流是什么?异步操做之间,又能够认为成是同步的,上一个异步执行完以后,才能够执行下一个异步程序,这时候须要一个函数来控制这个异步的流程。

// 若是task1完成了再作task2,而后交上task1,再交上task2。

// 如果以下:只能经过setTimeOut的时间控制实现异步。
function task1(next) {
setTimeout(function(){
console.log("Task1 done");
},100)
}

function task2(next) {
setTimeout(function(){
console.log("Task2 done");
},200)
}

function endTask1(next) {
setTimeout(function(){
console.log("send task1");
},300)
}

function endTask2(next) {
setTimeout(function(){
console.log("send task2");
},400)
}

task1()
task2()
endTask1()
endTask2()
// 可是若是执行完每一个步骤的时间相同甚至task1须要用时最多怎么办呢?

// 以下:

setTimeout(function() {
console.log("Task1 done");
setTimeout(function(){
console.log("Task2 done");
setTimeout(function(){
console.log("send task1");
// ....... 陷入了回调地狱
},500)
},500)
},500)

// 使用generat解决

function task1(next) {
setTimeout(function(){
console.log("Task1 done");
next();//完成后须要执行的下一件事
},500)
}

function task2(next) {
setTimeout(function(){
console.log("Task2 done");
next();//完成后须要执行的下一件事
},500)
}

function endTask1(next) {
setTimeout(function(){
console.log("send task1");
next();//完成后须要执行的下一件事
},500)
}

function endTask2(next) {
setTimeout(function(){
console.log("send task2");
next();//完成后须要执行的下一件事
},500)
}

function run(fn) {
let gen = fn();//fn:tack;fn(): task();
function next() {
let result = gen.next();//第一轮:执行yield task1;其中task1是个函数。因此,下面result.value是个函数。
if (result.done) {
return;
}
// 第一轮:result.value是个函数,表明了task1,参数传入next函数名,实现了在task1中调用了run中的next函数,进而进行第二轮。
result.value(next);
};
next();
}

function* task() {
yield task1;
yield task2;
yield endTask1;
yield endTask2;
}

run(task);

// 控制台每隔500ms分别输出 "Task1 done" ,"Task2 done" ,"send task1" ,"send task2"

相关文章
相关标签/搜索