从 setTimeout 调用生成器函数
Calling generator function from setTimeout
以下 js 代码在 firefox、chrome 和 nodejs 的开发者控制台中失败。无法弄清楚为什么?
function* x() {}
let y = x()
setTimeout(y.next, 100)
Firefox 错误
TypeError: CallGeneratorMethodIfWrapped method called on incompatible
Window
错误 chrome
Uncaught TypeError: Method [Generator].prototype.next called on
incompatible receiver #
at 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)
当您将 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);
以下 js 代码在 firefox、chrome 和 nodejs 的开发者控制台中失败。无法弄清楚为什么?
function* x() {}
let y = x()
setTimeout(y.next, 100)
Firefox 错误
TypeError: CallGeneratorMethodIfWrapped method called on incompatible Window
错误 chrome
Uncaught TypeError: Method [Generator].prototype.next called on incompatible receiver # at 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)
当您将 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);