从setTimeout调用生成器函数

时间:2019-03-20 17:49:35

标签: javascript node.js es6-generator

以下js代码在firefox,chrome和nodejs的开发人员控制台中也失败。无法找出原因?

function* x() {}
let y = x()
setTimeout(y.next, 100)

firefox错误

  

TypeError:调用了不兼容的CallGeneratorMethodIfWrapped方法   窗口

Chrome出现错误

  

未捕获的TypeError:调用了方法[Generator] .prototype.next   不兼容的接收器       在下一个()

node.js中的错误

timers.js:475
    timer._onTimeout();
          ^

TypeError: Method [Generator].prototype.next called on incompatible receiver #<Timeout>
    at Timeout.next [as _onTimeout] (<anonymous>)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5)

1 个答案:

答案 0 :(得分:3)

y作为要调用的函数传递时,对象y.next丢失。您可以这样做:

setTimeout(y.next.bind(y), 100)

当您传递y.next时,它会到达y对象上并获得对next函数的引用,而它只会传递对next函数的引用。它是对next函数的通用引用,该函数与y对象完全没有关联。然后,稍后触发setTimeout()时,它仅自己调用next函数,并且函数调用中未使用对象y。这意味着执行next时,this的值将为undefined,而不是适当的y对象。

您可以想象这样做:

let x = y.next;
setTimeout(x, 100);

y无关的内容已传递给setTimeout()。我们将把next()方法称为普通函数。如果您这样做,可能会遇到相同的问题:

let x = y.next;
x();

根据其设计,setTimeout()仅调用fn()中的函数。它不会像y.next()中那样调用方法。要调用方法,必须在实际的函数调用中使用对象引用,如在y.next()中看到的那样。 setTimeout()不会这样做。它只是调用函数。

因此,.bind()创建了一个小的小存根函数,然后将为您正确调用它。因此,如我上面所示,使用它类似于:

let x = function() {
    y.next();
}
setTimeout(x, 100);

或者,内联版本:

setTimeout(function() {
    y.next();
}, 100);