javascript与生成器交互

使用yield表达式从生成器中返回多个值,但生成器远比这更加强大!我们还能向生成器发送值,从而实现双向通信!使用生成器我们能够生成中间结果,在生成器以外我们也能够使用该结果进行任何操作,然后,一旦准备好了,就能够把整个新计算得到的数据再完完整整返回给生成器。

作为生成器函数发送值

向生成器发送值的最简单方法如其他函数一样,调用函数并传入实参。
    console.log('--------------向生成器发送数据及从生成器接收数据------------');
    //生成器可以像其他函数一样接收标准参数
    function* NinjaGenerator(action) {
    //奇迹出现了,产生一个值的同时,生成器会返回一个中间计算结果。通过带有参数的调用迭代器的next方法,我们可以将数据传递回生成器。
    const imposter = yield ('Hattori ' + action);

    //传递回的值将成为yield表达式的返回值,因此imposer的值是Hanzo
    if (imposter === 'Hanzo') {
          console.log('The generator has been infiltrated!');
          yield ("Yoshi (" + imposter + ") " + action);
        }
    }

    //普通的参数传递
    //触发生成器的执行,并检查返回值是否正确
    const ninjaIterator = NinjaGenerator('skulk');

    //触发生成器执行,并检测返回值是否正确
    const result1 = ninjaIterator.next();
    if (result1.value === 'Hattori skulk') {
      console.log('Hattori is skulking!');
    }

    //将数据作为next方法的参数传递给生成器,并检测返回值是否符合预期值。
    const result2 = ninjaIterator.next('Hanzo');
    if (result2.value === 'Yoshi (Hanzo) skulk') {
      console.log('We have an imposter!');
    }

 

使用next方法向生成器发送值

除了在第一次调用生成器的时候向生成器提供数据,我们还能通过next方法向生成器传入参数。在这个过程中,我们把生成器函数从挂起状态恢复到执行状态。在当前挂起的生成器中,生成器把这个传入的值用于整个yeild表达式。

在上述代码中,我们调用了两次ninjaIterator的next方法。第一次调用ninjaIterator.next(),请求了生成器的第一个值。由于生成器还没开始执行,这次调用则启动了生成器,对表达式“Hattori ” + action进行求值,得到了值"Hattori skulk",并将该生成器的执行挂起。

首次调用ninjaIterator.next()方法向生成器请求一个新值,在yield表达式的位置返回了Hattori skulk,并挂起执行。第二次调用ninjaIterator.next('Hanzo')又请求一个新值,但它同升湖向生成器发送了实参Hanzo。这个只会在整个yield表达式中使用,同时,imposter变量也就包含了字符Hanzo

然而第二次调用ninjaIterator的next方法则发生了有趣的事:ninjaIterator.next('Hanzo')。这一次,我们使用next方法将计算得到的值又传递会生成器。生成器函数耐心等待着,在表达式yield('Hattoti' + action)位置挂起,故而值Hanzo作为参数传入了next()方法,并用作整个yield表达式的值。上述代码中,也就是表示语句imposter = yield ('Hattoti' + action)中的变量imposter会以值Hazo作为结尾。

以上展示了如何在生成器中双向通信。我们通过yield语句从生成器中返回值,再使用迭代器的next()方法把值传递会生成器。

注意:

next方法为等待中的yield表达式提供了值,所以,如果没有等待中的yield表达式,也就没有什么值能应用的。基于这个基因,我们无法通过第一次调用next方法来向生成器提供该值。但记住,如果需要为生成器提供一个初始值,你可以调用生成器自身,就像NinjaGenerator('skulk')。

 

抛出异常

还有一种稍微不那么正统的方式将值应用到生成器上:通过抛出一个异常。每个迭代器除了有一个next方法,还抛出一个方法。
console.log("--------------------向生成器抛出异常--------------------");
function* NinjaGenerator() {
  try{
    yield 'Hattori';
    console.log("The expected exception did not occur!");
  } catch (e) {
    console.log("e:" + JSON.stringify(e));
    if (e === 'Catch this!') {
      console.log("Aha! We caught an exception!");
    }
  }
}

const ninjaIterator = NinjaGenerator();

//从生成器拉取一个值
const result1 = ninjaIterator.next();
if (result1.value === 'Hattori') {
  console.log("We got Hattori!");
}

//向生成器抛出一个异常
ninjaIterator.throw("Catch this!");

 

我们把整体函数体用一个try-catch块包裹起来了。

function* NinjaGenerator() {

try{

yield 'Hattori';

console.log("The expected exception did not occur!");

} catch (e) {

console.log("e:" + JSON.stringify(e));

if (e === 'Catch this!') {

console.log("Aha! We caught an exception!");

}

}

}

通过创建一个迭代器继续执行,然后从生成器中获取一个值:

const ninjaIterator = NinjaGenerator();

//从生成器拉取一个值

const result1 = ninjaIterator.next();

最后,通过使用在所有迭代器上都有效的throw方法,我们可以向生成器抛出一个异常:

ninjaIterator.throw("Catch this!");

这个能让我们把异常抛回生成器的特性初看可能有点奇怪。为什么要进行这样的操作呢?我们将使用这个特性来改善异步服务器端的通信。

 

参考《JavaScript忍者秘籍》

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/85633341