JavaScript中的yield关键字是什么?

mck*_*k89 218 javascript yield keyword

我在JavaScript中听说过"yield"关键字,但我发现它的文档很差.有人可以解释我(或推荐一个解释的网站)其用途及其用途吗?

bis*_*hop 185

迟到的回答,可能yield现在每个人都知道,但一些更好的文档已经出现.

修改James Long的"Javascript未来:发电机"中的一个例子,用于官方Harmony标准:

function * foo(x) {
    while (true) {
        x = x * 2;
        yield x;
    }
}
Run Code Online (Sandbox Code Playgroud)

"当你调用foo时,你会得到一个具有下一个方法的Generator对象."

var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
Run Code Online (Sandbox Code Playgroud)

所以yield有点像return:你得到回报. return x返回值的值x,但yield x返回一个函数,它为您提供了迭代下一个值的方法.如果您有可能要在迭代期间中断的潜在内存密集型过程,则非常有用.

  • 有帮助,但我猜你的`函数*foo(x){`那里 (12认同)
  • @RanaDeep:[函数语法扩展为添加*可选*`*`标记](http://wiki.ecmascript.org/doku.php?id=harmony:generators).您是否需要它取决于您返回的未来类型.细节很长:[GvR为Python实现解释](https://groups.google.com/forum/#!msg/python-tulip/bmphRrryuFk/aB45sEJUomYJ),在此基础上建模Javascript实现.使用`function*`总是正确的,虽然在某些情况下比使用`yield`的`function`略微开销. (8认同)
  • @MuhammadUmer Js终于成为了一种你可以实际使用的语言.它被称为进化. (3认同)
  • 这很有帮助,谢谢你的例子. (2认同)

Mat*_*all 81

MDN文档是相当不错的,海事组织.

包含yield关键字的函数是一个生成器.当你调用它时,它的形式参数绑定到实际的参数,但它的实体并没有被实际评估.而是返回一个generator-iterator.每次调用generator-iterator的next()方法都会执行迭代算法的另一次传递.每个步骤的值是yield关键字指定的值.将yield视为返回的generator-iterator版本,指示算法的每次迭代之间的边界.每次调用next()时,生成器代码将从yield之后的语句中恢复.

  • 我不清楚.它错过了一个例子. (185认同)
  • 如果(a)它是"非常糟糕的文档"的副本,提问者称之为和(b)它没有任何帮助,那么这是如何获得约80赞成的?下面有更好的答案. (16认同)
  • 在这里引用MDN有什么意义?我想每个人都可以在MDN上阅读.访问https://davidwalsh.name/promises以了解有关它们的更多信息. (4认同)
  • 如果有人要求解释,只需复制粘贴文档是完全没用的.提示意味着您已经在文档中搜索过,但您并不理解它们. (4认同)
  • MDN 文档是关于 JS 最难以理解的,当你只想知道它“做什么”时,使用了很多技术术语,仅此而已。 (4认同)
  • @NicolasBarbulesco如果您点击MDN文档,有一个非常明显的例子. (2认同)

Lea*_*der 53

简化/阐述Nick Sotiros的答案(我认为很棒),我认为最好描述一下如何开始编码yield.

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

它的实现方式是引入一个协同例程的概念,这个函数可以自动停止/暂停,直到它得到它需要的东西.在javascript中,这表示为function*.只有function*功能可以使用yield.

这是一些典型的javascript:

loadFromDB('query', function (err, result) {
  // Do something with the result or handle the error
})
Run Code Online (Sandbox Code Playgroud)

这很笨重,因为现在你所有的代码(显然需要等待这个loadFromDB调用)都需要在这个丑陋的回调中.由于一些原因,这很糟糕......

  • 你的所有代码都缩进了一个级别
  • 你有这个目的}),你需要跟踪到处
  • 所有这些额外的function (err, result)行话
  • 不完全清楚你要这样做来分配一个值 result

另一方面,借助于良好的协同例程框架yield,所有这些都可以在一行中完成.

function* main() {
  var result = yield loadFromDB('query')
}
Run Code Online (Sandbox Code Playgroud)

因此,当需要等待变量和事物加载时,您的主函数将在必要时生成.但是现在,为了运行它,你需要调用一个普通的(非协程函数).一个简单的协同例程框架可以解决这个问题,所以你要做的就是运行:

start(main())
Run Code Online (Sandbox Code Playgroud)

并开始定义(来自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
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以拥有更易读,更易删除的漂亮代码,而且无需使用缩进,函数等.

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

function* main() {
  console.log(yield function(cb) { cb(null, "Hello World") })
}
Run Code Online (Sandbox Code Playgroud)

会打印"Hello World".所以你可以yield通过简单地创建相同的函数签名(没有cb)并返回来实际将任何回调函数转换为使用function (cb) {},如下所示:

function yieldAsyncFunc(arg1, arg2) {
  return function (cb) {
    realAsyncFunc(arg1, arg2, cb)
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 对于已经到处使用`yield`的人来说,我确信这比回调更有意义,但是我没有看到它比回调更可读. (7认同)
  • 那篇文章很难理解 (3认同)
  • 优秀的答案,应该是顶尖的. (2认同)

noe*_*han 53

这真的很简单,这是它的工作原理

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

let out1 = _process.next();
console.log(out1);

let out2 = _process.next();
console.log(out2);

let out3 = _process.next(90);
console.log(out3);
Run Code Online (Sandbox Code Playgroud)

let _process = process();

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

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

但是,虽然yield执行此暂停并恢复行为,但它可以返回一些结果,{value: any, done: boolean} 根据之前的函数我们没有发出任何值.如果我们探索先前的输出,它将显示相同{ value: undefined, done: false } 的值undefined.

让我们深入了解yield关键字.(可选)您可以添加表达式并设置分配默认可选值.(官方doc语法)

[rv] = yield [expression];
Run Code Online (Sandbox Code Playgroud)

expression:从生成器函数返回的值

yield any;
yield {age: 12};
Run Code Online (Sandbox Code Playgroud)

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

只需使用此机制将参数传递给process()函数,即可执行不同的屈服部分.

let val = yield 99; 

_process.next(10);
now the val will be 10 
Run Code Online (Sandbox Code Playgroud)

现在就试试

用法

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

参考文献:


Dav*_*vid 18

给出一个完整的答案: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
Run Code Online (Sandbox Code Playgroud)

但是这也是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
Run Code Online (Sandbox Code Playgroud)

这工作,作为值2分配给y由它发送到发电机,它停在第一个收益率(其中返回后0).

这使我们能够获得一些非常时髦的东西.(查找协程)


Mat*_*hen 16

它用于迭代器生成器.基本上,它允许您使用过程代码创建(可能是无限的)序列.请参阅Mozilla的文档.


Han*_*bib 12

Yield javaScript 函数中的关键字使其成为生成器,

JavaScript 中的生成器是什么?

生成器是产生一系列结果而不是单个值的函数,即您生成一系列值

意义生成器帮助我们与帮助迭代器异步工作,哦,现在黑客迭代器是什么?真的吗?

迭代器是平均的,通过它我们可以一次访问一个项目

迭代器从哪里帮助我们一次访问一个项目?它帮助我们通过生成器函数访问项目,生成器函数是我们使用yield关键字的那些,yield 关键字帮助我们暂停和恢复函数的执行。

这是快速示例:

function *getMeDrink() {

    let question1 = yield 'soda or beer'; // execution will pause here because of yield
       
    if (question1 == 'soda') {
        return 'here you get your soda';
    }

    if (question1 == 'beer') {

        let question2 = yield 'What\'s your age'; // execution will pause here because of yield

        if (question2 > 18) {
            return "ok you are eligible for it";
        } else {
            return "Shhhh!!!!";
        }
    }
}

let _getMeDrink = getMeDrink(); // initialize it

_getMeDrink.next().value; // "soda or beer"

_getMeDrink.next('beer').value; // "What's your age"

_getMeDrink.next('20').value; // "ok you are eligible for it"

_getMeDrink.next().value; // undefined

Run Code Online (Sandbox Code Playgroud)

让我简单解释一下发生了什么

您注意到每个yield关键字的执行都被暂停,我们可以yield在迭代器的帮助下首先访问.next()

这一次迭代到所有yield关键字,然后在没有更多yield关键字时返回 undefined在简单的单词中您可以说yield关键字是断点,其中函数每次暂停并且仅在使用迭代器调用它时恢复我们的情况:_getMeDrink.next()这是示例帮助我们访问函数中的每个断点的迭代器。

生成器示例: async/await

如果你看到你的实现async/await你会看到generator functions & promises 被用来制作async/await工作请指出任何建议是受欢迎的。

  • 最有教养的答案!! (2认同)

Nic*_*ros 6

yield 也可以用一个协程框架来消除回调地狱.

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());
Run Code Online (Sandbox Code Playgroud)


nik*_*san 5

使用yield关键字的斐波那契数列生成器。

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

var fibonacciGenerator = fibonacci();
fibonacciGenerator.next().value; // 0 
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 2 
Run Code Online (Sandbox Code Playgroud)