【问题标题】:Calling generator function from setTimeout [duplicate]从 setTimeout 调用生成器函数 [重复]
【发布时间】:2019-03-20 17:49:35
【问题描述】:

以下 js 代码在 firefox、chrome 和 nodejs 的开发者控制台中也失败。不知道为什么?

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

火狐浏览器出错

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

chrome 中的错误

Uncaught TypeError: Method [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)

【问题讨论】:

标签: javascript node.js es6-generator


【解决方案1】:

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

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

【讨论】:

  • 或者传递一个 lambda:setTimeout(() =&gt; y.next(), 100)。 @VLAZ:当然,比起匿名函数,我更倾向于使用 lambda,但这是一个有效的选择
  • @Caramiriel 即使是普通函数也可以工作function() { y.next() } - 在任何一种情况下,调用都会正确设置上下文。
  • @jfriend00 感谢您的回答。你能解释一下为什么 y 的上下文是必要的吗? y.next 已经是一个函数,为什么调用 y.next 会失败。
  • "y.next 已经是一个函数" 更正它是一个方法,这正是它重要的原因。对术语的快速解释会有所帮助 - function 是一个未绑定的过程,(通常)接受一些输入并产生输出。 method 从远处看几乎是一样的——它仍然接受输入并产生输出,但它绑定到一个 object。所以,简而言之,如果你调用someObj.something(),它是一个方法,如果你调用something(),它是一个函数。一个方法可能依赖于它的上下文——对象。因此,取消关联上下文可能会破坏方法。
  • @chinoy 可能最重要的区别是 methods 将使用 this 来访问它们所属的对象。这就是为什么this 被称为上下文的原因——它是 过程当前范围之外的过程的一部分,但代码使用了一些东西。例如。打电话给this.someVariable++。没有上下文,代码中断或行为异常。一个方法可能不使用上下文,在这种情况下可以安全地分离它,但它是否使用并不容易。
猜你喜欢
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-14
  • 2016-07-24
  • 2020-04-23
  • 2017-11-23
相关资源
最近更新 更多