JavaScript中的yield关键字是什么?

304
我听说过 JavaScript 中的 "yield" 关键字。它有什么用途,我该如何使用它?

他可能是指“Yield”。http://bytes.com/topic/python/answers/685510-yield-keyword-usage - ant
6
这在MDN中有解释,但我认为这只适用于 Firefox,对吗?它的可移植性如何?是否有方法可以在 Chrome 或 Node.js 上实现这个功能?附注:抱歉,这是JavaScript v1.7+,所以在寻找支持时要查看该属性。 - Trylks
3
自从Node v0.11.2版本起,生成器已经可用。 - Janus Troelsen
1
@JanusTroelsen,然而,只有在标志后面。它们在ioJS中得到本地支持。 - Dan
1
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield - chharvey
1
注意:yield不受Internet Explorer支持。 - Krisztián Balla
15个回答

1
我也在尝试理解yield关键字。基于我目前的理解,在生成器中,yield关键字的作用类似于CPU上下文切换。当运行yield语句时,所有状态(例如局部变量)都将被保存。除此之外,还会向调用者返回一个直接结果对象,如{ value: 0, done: false }。调用者可以使用这个结果对象来决定是否通过调用next()来“唤醒”生成器(调用next()是迭代执行)。另一个重要的事情是它可以为本地变量设置值。这个值可以在“唤醒”生成器时由'next()'调用者传递。例如,it.next('valueToPass'),就像这样:"resultValue = yield slowQuery(1);" 就像唤醒下一个执行时,调用者可以将一些运行结果注入到执行中(将其注入到本地变量中)。因此,对于这个执行,有两种状态:上次执行保存的上下文和这次执行触发的注入值。
因此,有了这个功能,生成器可以对多个异步操作进行排序。第一个异步查询的结果将通过设置本地变量(上面示例中的resultValue)传递给第二个查询。只能通过第一个异步查询的响应来触发第二个异步查询。然后,第二个异步查询可以检查本地变量值以决定下一步操作,因为本地变量是从第一个查询的响应中注入的值。
异步查询的困难之处在于:
  1. 回调地狱
  2. 除非将其作为回调中的参数传递,否则会失去上下文。
yield 和 generator 可以同时解决这两个问题。
如果没有 yield 和 generator,则需要使用嵌套回调和参数作为上下文来处理多个异步查询,这不易于阅读和维护。
以下是在 nodejs 中运行的链接异步查询示例:
const axios = require('axios');

function slowQuery(url) {        
    axios.get(url)
    .then(function (response) {
            it.next(1);
    })
    .catch(function (error) {
            it.next(0);
    })
}

function* myGen(i=0) {
    let queryResult = 0;

    console.log("query1", queryResult);
    queryResult = yield slowQuery('https://google.com');


    if(queryResult == 1) {
        console.log("query2", queryResult);
        //change it to the correct url and run again.
        queryResult = yield slowQuery('https://1111111111google.com');
    }

    if(queryResult == 1) {
        console.log("query3", queryResult);
        queryResult =  yield slowQuery('https://google.com');
    } else {
        console.log("query4", queryResult);
        queryResult = yield slowQuery('https://google.com');
    }
}

console.log("+++++++++++start+++++++++++");
let it = myGen();
let result = it.next();
console.log("+++++++++++end+++++++++++");

以下是运行结果:

+++++++++++开始+++++++++++

查询1 0

+++++++++++结束+++++++++++

查询2 1

查询4 0

下面的状态模式可以对上面的示例执行类似的操作:
const axios = require('axios');

function slowQuery(url) {
    axios.get(url)
        .then(function (response) {
            sm.next(1);
        })
        .catch(function (error) {
            sm.next(0);
        })
}

class StateMachine {
        constructor () {
            this.handler = handlerA;
            this.next = (result = 1) => this.handler(this, result);
        }
}

const handlerA = (sm, result) => {
                                    const queryResult = result; //similar with generator injection
                                    console.log("query1", queryResult);
                                    slowQuery('https://google.com');
                                    sm.handler = handlerB; //similar with yield;
                                };

const handlerB = (sm, result) => {
                                    const queryResult = result; //similar with generator injection
                                    if(queryResult == 1) {
                                        console.log("query2", queryResult);
                                        slowQuery('https://1111111111google.com');
                                    }
                                    sm.handler = handlerC; //similar with yield;
                                };

const handlerC = (sm, result) => {
                                    const queryResult = result; //similar with generator injection;
                                    if (result == 1 ) {
                                        console.log("query3", queryResult);
                                        slowQuery('https://google.com');
                                    } else {
                                        console.log("query4", queryResult);
                                        slowQuery('https://google.com');
                                    }
                                    sm.handler = handlerEnd; //similar with yield;
                                };

const handlerEnd = (sm, result) => {};

console.log("+++++++++++start+++++++++++");
const sm = new StateMachine();
sm.next();
console.log("+++++++++++end+++++++++++");

以下是运行结果:

+++++++++++开始+++++++++++

查询1 0

+++++++++++结束+++++++++++

查询2 1

查询4 0


1
嗨,如果你能看到这里,意味着之前的回答都没有满足你的期望,所以我会简单解释一下...
function * y(){
    const r = yield;
    /** program continue after next() call... **/
}

首先...
y() 不是一个函数,而是一个生成器。
生成器被称为生成器,因为它们可以生成多个返回值。
当遇到 'yield' 时,生成器会暂停执行。
您可以添加任意数量的 yield。
在调用 next(见下文) 之前,yield 后面的所有代码都不会执行。
生成器可以与 async/await 一起使用。
与函数不同,生成器可以具有任意数量的返回值。
调用 yield 就像调用 return。
您可以使用 .value 属性从 yield 获取值(见下文)。
请记住,第一次调用 next() 只会达到 yield,并等待下一个 "next()" 调用来处理实际操作,因此... 调用.next() 将达到断点,随后的调用.next('这里放置一些内容') 将在执行暂停后执行某些操作...
function * f(){
       const u = yield; // pause here ...
       return u; // something with u after 2nd next() call (see below)
    }

const call = f();
call.next(); // will get to yield(first yield) and wait
call.next('wow'); // as we have 1 yield in the generator, the second next() call will reach the return point where you will get 'wow' as you passed a string 'wow' as the second next() call argument, you can obviously pass in whatever you want(callbacks, string, objects...)

希望我表达清楚并且易于理解...记住你可以在官方的MDN文档中搜索https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield

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

0
不要忘记非常有用的“生成器中的x”语法,以循环遍历生成器。根本不需要使用next()函数。
function* square(x){
    for(i=0;i<100;i++){
        x = x * 2;
        yield x;        
    }   
}

var gen = square(2);
for(x of gen){
   console.log(x);
}

这可能是因为生成器是一个迭代器。 - Coffeeholic

0
一个简单的例子:
const strArr = ["red", "green", "blue", "black"];

const strGen = function*() {
    for(let str of strArr) {
        yield str;
    }
};

let gen = strGen();

for (let i = 0; i < 5; i++) {
    console.log(gen.next())
}

//prints: {value: "red", done: false} -> 5 times with different colors, if you try it again as below:

console.log(gen.next());

//prints: {value: undefined, done: true}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接