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


当前回答

使用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 

其他回答

简化/详细阐述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)
  }
}

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

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

将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返回一个函数,它为您提供了一个迭代到下一个值的方法。如果您有一个潜在的内存密集型过程,您可能希望在迭代期间中断这个过程,那么这个方法很有用。

异步javascript调用之间的依赖关系。

另一个关于如何使用yield的好例子。

函数请求(url) { Axios.get (url).then((response) => { it.next(响应); }) } 函数* main() { Const result1 = yield request('http://some.api.com'); Const result2 = yield request('http://some.otherapi?Id =' + result1。id); console.log('您的响应是:' + result2.value); } Var it = main(); it.next ()

举个简单的例子:

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}

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