为什么生成器下一个函数不能是事件监听器的回调函数

Why can't the generators next function be a callback function for an event listener

我正在尝试使用生成器。当我尝试这段代码时,出现了意想不到的错误:

Uncaught TypeError: 方法 [Generator].prototype.next 在不兼容的接收器上调用 # 要么 TypeError:在不兼容的 HTMLButtonElement

上调用了 CallStarGeneratorMethodIfWrapped 方法

我的问题,它不起作用吗?这些错误消息背后的含义是什么?最重要的是;为什么 first().next 不作为普通函数处理?为什么 addEventListener 关心 first().next 函数的来源。在控制台中输入 first().next。它说功能。下面是一个与下一个类似的函数的注释,除了它总是产生相同的结果。

您可以尝试重现的代码:

<html>
<button id="test">Click</button>
<script>

var first = function* (){
    console.log("first click");
    yield true;
    console.log("second click");
    yield true;
};

document.getElementById("test").addEventListener('click', first().next);

/*var wouldwork = function (){
    console.log("would work");
    return { value: true, done: false };
    // same as the next returns
};*/
/*document.getElementById("test").addEventListener('click', wouldwork);*/
</script>
</html>

另一种选择是将 next 与正确的上下文放在另一个函数中。为此,我们将迭代器存储在一个变量中。

var iterator = first();

document.getElementById("test").addEventListener('click',

    function (event){return iterator.next();}

    //context of next is always the correct one

);

如果这种情况经常发生,最好创建一个名为 createNext 的新函数,returns 一个更纯函数式风格的 next 函数

var createNext = function (generatorFunction){

    var iterator = generatorFunction();

    return function() {

        return iterator.next();

    };

};



document.getElementById("test").addEventListener('click',

    createNext(first)

);

jsFiddle Demo

事件侦听的工作方式是它将使用 call 调用函数句柄并将 this 绑定从其执行上下文分配给被调用的函数句柄。所以 this 将被绑定为 next 被调用的上下文。这就是为什么它不像写的那样工作。

接下来是从生成器函数中实际获取函数进行迭代的问题。 "Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead."。这意味着是的,first().next 一个函数对象,但它不是您要传递的句柄。您只是想使用迭代器函数本身,但那将是 first(),那么如果您希望它每次都调用 next ,那将如何工作?

这里的一个选项是简单地获取生成器函数并稍后将迭代器函数作为绑定传递。为了保持迭代器函数在 .next 内部的绑定,您可以这样做:

document.getElementById("test").addEventListener('click', first().next.bind(first()));

这会将 first() 的迭代器函数绑定到迭代器函数的 .next 函数。有点乱。第一次调用 first() 公开迭代器函数,然后访问它的 next 函数,第二次调用简单地将 next 函数的 this 绑定到迭代器函数,否则当 eventListener 覆盖 this 绑定时该函数会被覆盖使用 call.

您可以在此处阅读有关这些生成器函数及其迭代器的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*