js之generator函数简单学习/复习

generator

先看看什麽是generator函数:

    function* fib(max) { // 与普通函数区别1: *
        var
            t,
            a = 0,
            b = 1,
            n = 0;
        while (n < max) {
            yield a; // 与普通函数区别2: 使用yield表达式
            [a, b] = [b, a + b];
            n ++;
        }
        return;
    }
	// 第一种方法执行
    var f = fib(5); // 仅仅是创建了一个generator对象,还没有去执行它
    // f.next()才开始真正运行,它的作用是会把yield后的值包装成固定对象返回
    console.log(f.next()); // {value: 0, done: false}
    console.log(f.next()); // {value: 1, done: false}
    console.log(f.next()); // {value: 1, done: false}
    console.log(f.next()); // {value: 2, done: false}
    console.log(f.next()); // {value: 3 , done: false}
    // 运行结束后,done值变为 true,返回的值变成 undefined
    console.log(f.next()); // {value: undefined, done: true}
	// 第二种方法执行
    for (var x of fib(10)) 
    console.log(x); // 依次输出0, 1, 1, 2, 3, ...

generator和普通函数相比,因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数。

yield

代码里边有个 yield,我们来看看它是如何工作使用的:

  • Generator函数返回的Iterator运行的过程中,如果遇到了yield就会把yield后边的值返回,然后函数暂停执行直到下一个next()方法开始执行,函数才会从上次暂停的位置重新开始。
  • yield可以和return一起使用,也可以不使用return
  • yieldreturn一起使用时,return的值会作为最后返回的值,如果有yield出现在return的后面,那部分就是失效的。
  • yield只能在generator函数的场景下使用
  • yield*Generator函数嵌套时使用,例子如下:
function* foo() {
    yield 0;
    yield 1;
}
function* bar() {
	yield 'x';
	yield* foo(); // yield* 函数
	yield 'y';
}
for (let v of bar()){
    console.log(v);
};

next()

  • 执行next()方法后得到的返回值结构为:
{
    value : ... ,
    done : false // done的值为一个布尔值, 如果Interator未遍历完毕, 他会返回false, 否则返回true;
}
  • next()方法可以设置参数,这个参数会当作上个yield语句的返回值
  • next()的参数在异步处理中非常重要,因为这种时候需要上一个异步的结果
function *foo2(x) {
      var y = 2 * (yield (x + 1));
      var z = yield (y / 3);
      return (x + y + z);
  }

  var it2 = foo2( 5 );

  // 异步情况下若有参数
  console.log( it2.next() );       // { value:6, done:false }
  console.log( it2.next(12) );   // { value:8, done:false } // 相当于从 var y = 2 * 12 开始执行
  console.log( it2.next(13) );   // { value:42, done:true }

  var it3 = foo2( 5 );

  console.log( it3.next() );       // { value:6, done:false }
  console.log( it3.next() );   // { value:NaN, done:false } // 无参数时,相当于var y = 2 * NaN
  console.log( it3.next() );   // { value:NaN, done:true }

Generator函数与 throw()

  • 先复习一下有关 try-catchthrow的相关知识:

    • try 语句允许您定义一个代码块,以便在执行时检测错误。
    • catch 语句允许你定义一个要执行的代码块,如果 try 代码块中发生错误。
        try {
         供测试的代码块
    }
     catch(err) {
         处理错误的代码块
    } 
    
    • throw 语句允许创建自定义错误并抛出它
    • 因此如果把 throw 与 try 和 catch 一同使用,就可以控制程序流并生成自定义错误消息。例如:
     x = document.getElementById("demo").value;
        try { 
            if(x == "") throw "空的";
             if(isNaN(x)) throw "不是数字";
             x = Number(x);
            if(x < 5) throw  "太小";
            if(x > 10) throw "太大";
        }
        catch(err) {
            message.innerHTML = "输入是 " + err;
        }
    
  • 如果Generator函数内包含try-catch和throw,当yield表达式在try内部, 那么如果执行Generator生成器的throw()方法时,这个错误会被内部的try{}catch(){}捕获

var g = function* () {
    while(true) {
        try {
            yield;
        } catch (e) {
            console.log('内部捕获', e);
        }
    }
};

var i = g();
i.next();

try {
    i.throw('a');
    i.throw('b');
} catch (e) {
    console.log('外部捕获', e);
}
// 内部捕获 a
// 内部捕获 b

return()

如果执行Iterator的return()方法, 那么这个迭代器的返回会被强制设置为迭代完毕

function* gen() {
    yield 0;
    yield 1;
    yield 2;
    yield 3;
};
let g = gen();
console.log(g.return("heheda")); //输出:{ value: 'heheda', done: true }

generator与Ajax

// 之前臃肿的异步回调形式
ajax('http://url-1', data1, function (err, result) {
    if (err) {
        return handle(err);
    }
    ajax('http://url-2', data2, function (err, result) {
        if (err) {
            return handle(err);
        }
        ajax('http://url-3', data3, function (err, result) {
            if (err) {
                return handle(err);
            }
            return success(result);
        });
    });
});
// 利用generator的Ajax改为如下代码,意义相同但是大幅缩减:

try {
    r1 = yield ajax('http://url-1', data1); // 当捕获到异常时catch发挥作用时,
    // 后续的代码就不再执行下去
    r2 = yield ajax('http://url-2', data2);
    r3 = yield ajax('http://url-3', data3);
    success(r3);
}
catch (err) {
    handle(err);
}

使用小例子

生成一个自增的ID,编写一个next_id()函数(不得使用闭包和全局变量)

function* next_id() {
    var num = 0;
    while(true){
        yield num++;
    }
}
发布了46 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yuanfangyoushan/article/details/100026369