我听说过JavaScript中的“yield”关键字,但我发现关于它的文档非常糟糕。有人能给我解释一下(或者推荐一个解释它的网站)它的用法和用途吗?


当前回答

在学习yield之前,您需要了解生成器。生成器是使用函数*语法创建的。Generator函数不执行代码,而是返回一种称为Generator的迭代器。当使用下一个方法给出一个值时,生成器函数将继续执行,直到遇到yield关键字。使用yield返回一个包含两个值的对象,一个是value,另一个是done(布尔值)。该值可以是数组、对象等。

其他回答

这真的很简单,它是这样工作的

Yield关键字只是帮助在任何时间异步暂停和恢复一个函数。 此外,它还有助于从生成器函数返回值。

以这个简单的生成器函数为例:

function* process() {
    console.log('Start process 1');
    console.log('Pause process2 until call next()');

    yield;

    console.log('Resumed process2');
    console.log('Pause process3 until call next()');

    let parms = yield {age: 12};
    console.log("Passed by final process next(90): " + parms);

    console.log('Resumed process3');
    console.log('End of the process function');
}

Let _process = process();

在调用_process.next()之前,它不会执行前两行代码,然后第一个yield将暂停函数。 要继续该函数直到下一个暂停点(yield关键字),需要调用_process.next()。

您可以将多个yield看作是javascript调试器中单个函数中的断点。直到 你告诉导航下一个断点,它不会执行代码 块。(注意:不阻塞整个应用程序)

但是当yield执行暂停和恢复行为时,它也可以返回一些结果{value: any, done: boolean} 根据前面的函数,我们没有输出任何值。如果我们查看之前的输出,它将显示相同的{value: undefined, done: false} 值未定义。

让我们深入研究yield关键字。可选地,您可以添加表达式和设置分配一个默认可选值。(官方文档语法)

[rv] = yield [expression];

表达式:从生成器函数返回的值

yield any;
yield {age: 12};

rv:返回传递给生成器next()方法的可选值

简单地,您可以使用这种机制将参数传递给process()函数,以执行不同的yield部分。

let val = yield 99; 

_process.next(10);
now the val will be 10 

现在就试试

用法

懒惰的评价 无限的序列 异步控制流

引用:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield http://javascript.tutorialhorizon.com/2015/09/16/generators-and-yield-in-es6/ https://strongloop.com/strongblog/how-to-generators-node-js-yield-use-cases/

简化/详细阐述Nick Sotiros的答案(我认为非常棒),我认为最好描述一个人如何开始使用yield编码。

在我看来,使用yield的最大优点是它将消除我们在代码中看到的所有嵌套回调问题。一开始很难理解,这就是为什么我决定写下这个答案(为了我自己,也希望其他人!)

它的方法是通过引入协程的思想,这是一个可以自动停止/暂停的函数,直到它得到它需要的东西。在javascript中,用函数*表示。只有函数*函数可以使用yield。

下面是一些典型的javascript代码:

loadFromDB('query', function (err, result) {
  // Do something with the result or handle the error
})

这很笨拙,因为现在所有的代码(显然需要等待loadFromDB调用)都需要在这个丑陋的回调中。这很糟糕,有几个原因……

所有代码都缩进了一层 你有这一端}),你需要随时跟踪 所有这些额外的功能(错误,结果)术语 不太清楚你这样做是为了给result赋值

另一方面,使用yield,所有这些都可以在良好的协同例程框架的帮助下在一行中完成。

function* main() {
  var result = yield loadFromDB('query')
}

所以现在你的主函数会在必要的时候让步当它需要等待变量和东西加载时。但是现在,为了运行这个,你需要调用一个普通的(非协程函数)。一个简单的协程框架可以解决这个问题,所以你所要做的就是运行这个:

start(main())

开始是有定义的(来自Nick Sotiro的回答)

function start(routine, data) {
    result = routine.next(data);
    if(!result.done) {
        result.value(function(err, data) {
            if(err) routine.throw(err); // continue next iteration of routine with an exception
            else start(routine, data);  // continue next iteration of routine normally
        });
    }
}

现在,你可以拥有可读性更强、易于删除的漂亮代码,而且不需要修改缩进、函数等。

一个有趣的观察是,在这个例子中,yield实际上只是一个关键字,可以放在带有回调的函数之前。

function* main() {
  console.log(yield function(cb) { cb(null, "Hello World") })
}

将打印“Hello World”。因此,你可以通过简单地创建相同的函数签名(不带cb)并返回函数(cb){}来将任何回调函数转换为使用yield,如下所示:

function yieldAsyncFunc(arg1, arg2) {
  return function (cb) {
    realAsyncFunc(arg1, arg2, cb)
  }
}

希望有了这些知识,您可以编写更清晰、更易读且易于删除的代码!

在我看来,MDN文档非常好。

The function containing the yield keyword is a generator. When you call it, its formal parameters are bound to actual arguments, but its body isn't actually evaluated. Instead, a generator-iterator is returned. Each call to the generator-iterator's next() method performs another pass through the iterative algorithm. Each step's value is the value specified by the yield keyword. Think of yield as the generator-iterator version of return, indicating the boundary between each iteration of the algorithm. Each time you call next(), the generator code resumes from the statement following the yield.

迟回答,也许现在每个人都知道收益率,但一些更好的文件已经出现。

将James Long的《Javascript的未来:生成器》中的一个例子改编为官方的Harmony标准:

function * foo(x) {
    while (true) {
        x = x * 2;
        yield x;
    }
}

当你调用foo时,你会得到一个Generator对象,它有一个next 方法。”

var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16

收益率有点像回报,你会得到一些回报。Return x返回x的值,但yield x返回一个函数,它为您提供了一个迭代到下一个值的方法。如果您有一个潜在的内存密集型过程,您可能希望在迭代期间中断这个过程,那么这个方法很有用。

给出一个完整的答案:yield的工作原理类似于return,但在发电机中。

对于通常给出的例子,其工作原理如下:

function *squareGen(x) {
    var i;
    for (i = 0; i < x; i++) {
        yield i*i;
    }
}

var gen = squareGen(3);

console.log(gen.next().value); // prints 0
console.log(gen.next().value); // prints 1
console.log(gen.next().value); // prints 4

但是yield关键字还有第二个用途。它可以用来向生成器发送值。

为了澄清,举个小例子:

function *sendStuff() {
    y = yield (0);
    yield y*y;
}

var gen = sendStuff();

console.log(gen.next().value); // prints 0
console.log(gen.next(2).value); // prints 4

它的工作原理是,将值2赋给y,在它停止在第一个yield(返回0)后将其发送给生成器。

这使我们能够看到一些非常时髦的东西。(查协程)