• 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"

  • 相关阅读:
    javascript实现简单的轮播图片
    用struts实现简单的登录
    非非是
    javabean连数据库
    超级迷宫 nabc
    我的Time
    SQL SERVER 2008 评估期已过
    《架构漫谈》有感
    c#
    与String有关的强制转换
  • 原文地址:https://www.cnblogs.com/this-xiaoming/p/11613535.html
Copyright © 2020-2023  润新知