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"

相關文章
相關標籤/搜索