热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JavaScript中的yield关键字是什么?-What'stheyieldkeywordinJavaScript?

IheardaboutayieldkeywordinJavaScript,butIfoundverypoordocumentationaboutit.Cansom

I heard about a "yield" keyword in Javascript, but I found very poor documentation about it. Can someone explain me (or recommend a site that explains) its usage and what it is used for?

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

8 个解决方案

#1


80  

The MDN documentation is pretty good, IMO.

在我看来,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.

包含yield关键字的函数是生成器。当您调用它时,它的形式参数绑定到实际的参数,但是它的主体实际上并没有被计算。相反,返回生成器-迭代器。对生成器-迭代器的next()方法的每个调用都执行迭代算法的另一个传递。每一步的值都是由yield关键字指定的值。把yield看作是return的生成器-迭代器版本,表示算法每次迭代之间的边界。每次调用next()时,在yield之后的语句中恢复生成器代码。

#2


134  

Late answering, probably everybody knows about yield now, but some better documentation has come along.

回答晚了,现在大家可能都知道收益率了,但是一些更好的文档已经出现了。

Adapting an example from "Javascript's Future: Generators" by James Long for the official Harmony standard:

改编自James Long的《Javascript的未来:生成器》(Javascript’s Future: generator),适用于官方的和谐标准:

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

"When you call foo, you get back a Generator object which has a next method."

“当你调用foo时,你会得到一个生成器对象,它有一个下一个方法。”

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

So yield is kind of like return: you get something back. return x returns the value of x, but yield x returns a function, which gives you a method to iterate toward the next value. Useful if you have a potentially memory intensive procedure that you might want to interrupt during the iteration.

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

#3


43  

Simplifying/elaborating on Nick Sotiros' answer (which I think is awesome), I think it's best to describe how one would start coding with with yield.

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

In my opinion, the biggest advantage of using yield is that it will eliminate all the nested callback problems we see in code. It's hard to see how at first, which is why I decided to write this answer (for myself, and hopefully others!)

在我看来,使用yield的最大好处是它将消除我们在代码中看到的所有嵌套回调问题。很难想象一开始是怎么写的,这就是为什么我决定写这个答案(对我自己来说,希望对其他人也是如此!)

The way it does it is by introducing the idea of a co-routine, which is a function that can voluntarily stop/pause until it gets what it needs. In Javascript, this is denoted by function*. Only function* functions can use yield.

它的方法是引入共同例行程序的概念,这是一个可以自动停止/暂停直到它得到它需要的功能。在Javascript中,这用函数*表示。只有函数*函数可以使用yield。

Here's some typical Javascript:

这里有一些典型的Javascript:

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

This is clunky because now all of your code (which obviously needs to wait for this loadFromDB call) needs to be inside this ugly looking callback. This is bad for a few reasons...

这很麻烦,因为现在所有的代码(显然需要等待loadFromDB调用)都需要放在这个难看的回调中。这很不好,有几个原因……

  • All of your code is indented one level in
  • 所有代码都缩进了一个级别
  • You have this end }) which you need to keep track of everywhere
  • 你有这样的目的,你需要追踪到任何地方。
  • All this extra function (err, result) jargon
  • 所有这些额外的函数(呃,结果)术语
  • Not exactly clear that you're doing this to assign a value to result
  • 不清楚您这样做是为了给结果赋值

On the other hand, with yield, all of this can be done in one line with the help of the nice co-routine framework.

另一方面,在yield的帮助下,所有这些都可以在一行中完成。

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

And so now your main function will yield where necessary when it needs to wait for variables and things to load. But now, in order to run this, you need to call a normal (non-coroutine function). A simple co-routine framework can fix this problem so that all you have to do is run this:

现在你的主函数会在需要等待变量和东西加载时产生。但是现在,要运行这个函数,需要调用一个普通的(非coroutine函数)。一个简单的联合例程框架可以解决这个问题,所以你所要做的就是运行这个:

start(main())

And start is defined (from Nick Sotiro' answer)

start是定义的(从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
        });
    }
}

And now, you can have beautiful code that is much more readable, easy to delete, and no need to fiddle with indents, functions, etc.

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

An interesting observation is that in this example, yield is actually just a keyword you can put before a function with a callback.

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

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

Would print "Hello World". So you can actually turn any callback function into using yield by simply creating the same function signature (without the cb) and returning function (cb) {}, like so:

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

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

Hopefully with this knowledge you can write cleaner, more readable code that is easy to delete!

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

#4


26  

It's Really Simple, This is how it works

很简单,就是这样

  • yield keyword simply helps to pause and resume a function in any time asynchronously.
  • yield关键字可以帮助在任何时候异步地暂停和恢复函数。
  • Additionally it helps to return value from a generator function.
  • 此外,它还有助于从生成器函数返回值。

Take this simple generator function:

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

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()');

    yield;

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

let _process = process();

让_process =过程();

Until you call the _process.next() it wont execute the first 2 lines of code, then the first yield will pause the function. To resume the function until next pause point (yield keyword) you need to call _process.next().

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

You can think multiple yields are the breakpoints in a Javascript debugger within a single function. Until you tell to navigate next breakpoint it wont execute the code block. (Note: without blocking the whole application)

您可以认为多个收益是一个函数中的Javascript调试器中的断点。在您告诉导航下一个断点之前,它不会执行代码块。(注意:不阻塞整个应用程序)

But while yield performs this pause and resume behaviours it can return some results as well {value: any, done: boolean} according to the previous function we haven't emit any values. If we explore the previous output it will show the same { value: undefined, done: false } with value undefined.

但是,尽管yield执行了暂停和恢复行为,它也会返回一些结果,如{value: any, done: boolean}根据前面的函数,我们不会发出任何值。如果我们研究前面的输出,它将显示相同的{value: undefined, done: false},值为undefined。

Lets dig in to the yield keyword. Optionally you can add expression and set assign a default optional value. (Official doc syntax)

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

[rv] = yield [expression];

expression: Value to return from the generator function

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

yield any;
yield {age: 12};

rv: Returns the optional value that passed to the generator's next() method

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

let val = yield 99; 

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

Try It Now

现在试一试

Usages

用法

  • Lazy evaluation
  • 懒惰的评价
  • Infinite sequences
  • 无限的序列
  • Asynchronous control flows
  • 异步控制流

References:

引用:

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

#5


16  

It's used for iterator-generators. Basically, it allows you to make a (potentially infinite) sequence using procedural code. See Mozilla's documentation.

它是用于iterator-generators。基本上,它允许您使用过程代码创建(可能是无限的)序列。看到Mozilla的文档。

#6


15  

To give a complete answer: yield is working similar to return, but in a generator.

给出一个完整的答案:yield与return类似,但在生成器中。

As for the commonly given example, this works as follows:

对于一般的例子,如下所示:

function *squareGen(x) {
    var i;
    for (i = 0; i 

But theres also a second purpose of the yield keyword. It can be used to send values to the generator.

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

To clarify, a small example:

为了澄清这一点,举个小例子:

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

This works, as the value 2 is assigned to y, by sending it to the generator, after it stopped at the first yield (which returned 0).

当值2被赋值给y时,这个值就会被发送到生成器中,在第一个yield(返回0)停止之后。

This enables us to to some really funky stuff. (look up coroutine)

这能让我们得到一些非常有趣的东西。(查找协同程序)

#7


5  

yield can also be used to eliminate callback hell, with a coroutine framework.

yield还可以用于消除回调地狱,使用coroutine框架。

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
        });
    }
}

// with nodejs as 'node --harmony'
fs = require('fs');
function read(path) {
    return function(callback) { fs.readFile(path, {encoding:'utf8'}, callback); };
}

function* routine() {
    text = yield read('/path/to/some/file.txt');
    console.log(text);
}

// with mdn Javascript 1.7
http.get = function(url) {
    return function(callback) { 
        // make xhr request object, 
        // use callback(null, resonseText) on status 200,
        // or callback(responseText) on status 500
    };
};

function* routine() {
    text = yield http.get('/path/to/some/file.txt');
    console.log(text);
}

// invoked as.., on both mdn and nodejs

start(routine());

#8


3  

Fibonacci sequence generator using the yield keyword.

使用yield关键字的Fibonacci序列生成器。

function* fibbonaci(){
    var a = -1, b = 1, c;
    while(1){
        c = a + b;
        a = b;
        b = c;
        yield c;
    }   
}

var fibOnacciGenerator= fibbonaci();
fibonacciGenerator.next().value; // 0 
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 2 

推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了安全性要求高的真正密码随机数生成器的概念和原理。首先解释了统计学意义上的伪随机数和真随机数的区别,以及伪随机数在密码学安全中的应用。然后讨论了真随机数的定义和产生方法,并指出了实际情况下真随机数的不可预测性和复杂性。最后介绍了随机数生成器的概念和方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • 前段时间做一个项目,需求是对每个视频添加预览图,这个问题最终选择方案是:用canvas.toDataYRL();来做转换获取视频的一个截图,添加到页面中,达到自动添加预览图的目的。 ... [详细]
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
author-avatar
堕天使乖怪_546
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有