• ES6 Generator使用


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

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

    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,表明结束。

    // 经过上面的分析,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"

  • 相关阅读:
    Calling a parent window function from an iframe
    JSON with Java
    Posting array of JSON objects to MVC3 action method via jQuery ajax
    What's the difference between jquery.js and jquery.min.js?
    jquery loop on Json data using $.each
    jquery ui tabs详解(中文)
    DataTables warning requested unknown parameter
    Datatables 1.10.x在命名上与1.9.x
    jQuery 1.x and 2.x , which is better?
    DataTabless Add rows
  • 原文地址:https://www.cnblogs.com/this-xiaoming/p/11613535.html
Copyright © 2020-2023  润新知