在以下代码中:
function so() {
console.log('inside the timer')
}
function* sogen() {
const callback = yield;
setTimeout(callback, 2000);
return 1;
}
function() {
var gen = sogen();
gen.next(so), gen.next(so);
}()
为什么我从不使用功能so
?
答案 0 :(得分:4)
tl; dr;您需要在IIFE上加上括号,或者根本不使用IIFE。
您可以使用生成器,并且一旦添加了括号,一切都将正常运行。
请注意,您实际上并不需要IIFE来运行代码,但是下面的答案解释了为什么您的内容无法正常工作。
您遇到的主要问题是这段代码:
function() {
var gen = sogen();
gen.next(so);
gen.next(so);
}()
这将产生类似于以下内容的错误:
未捕获到的SyntaxError:意外令牌(
这里的问题是您试图将function declaration用作function expression。
来自MDN(重点是我):
函数表达式与函数语句非常相似,并且语法几乎相同(有关详细信息,请参见函数语句)。函数表达式和函数语句之间的主要区别是函数名称,可以在函数表达式中省略该名称以创建匿名函数。 函数表达式可以用作IIFE(立即调用函数表达式),该函数表达式在定义后立即运行。另请参阅关于功能的章节以获取更多信息。
这意味着要立即执行功能,您需要使用功能 expression 而不是 statement 。
编写函数表达式的一种常见方法是将函数包装在括号中
function a() { return 'a'; } // Function declaration
(function b() { return 'b'; }) // Function expression
要将其转换为IIFE,可以在末尾添加()
调用括号:
(function c() { return 'c'; })() // IIFE
将立即调用该函数。 请注意,我更喜欢将调用括号放在包装括号内,但这只是一种样式选择,并且以相同的方式工作:
(function c() { return 'c'; }()) // IIFE
以下是答案中的代码,以及包裹IIFE的括号:
function so() {
console.log('inside the timer');
}
function* sogen() {
const callback = yield;
setTimeout(callback, 2000);
return 1;
}
(function() {
const gen = sogen();
gen.next(so);
gen.next(so);
}())
或者,只需删除IIFE:
const gen = sogen();
gen.next(so);
gen.next(so);
或者如果您需要函数声明,请在下一行调用函数:
function run() {
const gen = sogen();
gen.next(so);
gen.next(so);
}
run();
答案 1 :(得分:3)
您提供的片段现在应该可以正常工作(IIFE中的语法错误除外)。为了清楚起见,我已对其进行了重写。
function so() {
console.log('inside the timer')
}
function* sogen()
{
const callback = yield; // line 1
setTimeout(callback, 2000); // line 2
return 1; // line 3
}
现在让我们看看如何使用从sogen
返回的迭代器来调用so
。
var iter = sogen();
我们创建了一个iterator。调用迭代器的next
方法,我们可以推进sogen
生成器的执行。
iter.next();
此调用之后,迭代器的状态现在冻结在sogen
的第1行上。遇到yield
,并且从{value: undefined, done: false}
调用返回了.next()
。现在,我们可以传递回调了。
iter.next(so);
我们已将回调传递到next
方法中,并且执行从第1行恢复。callback
变量现在具有so
函数的值。继续到第2行-setTimeout被调用。两秒钟后,我们的so
函数将被调用。但是在此之前,代码继续到第3行。.next(so)
调用返回{value: 1, done: true}
。现在我们等待。
两秒钟后,您应该看到inside the timer
已登录到控制台。
答案 2 :(得分:2)
在您的代码段中,sogen
不是常规函数,而是生成器,如*
所示。
您可以调用生成器以获取基本上是迭代器的迭代器,可以使用方法.next()
进行控制,并且每次遇到yield
关键字时都可以暂停其执行。
var it = sogen();
it.next();
您在那里(const callback = yield
)的分配将通过随后的.next()调用来解决,例如:
it.next(function myCallback() { /* ... */ });
然后,生成器将继续运行,直到下一个yield
或函数结束为止。
答案 3 :(得分:0)
这里您将生成器函数用作观察者。
在创建生成器对象时,实际上并没有调用它。
首次调用gen.next(so)时,它充当对生成器的调用,并且忽略传递给它的值。(第一次调用将执行提升到第一个yield。)
第二次调用gen.next(so)yield会收到“ function so(){}”函数,其余代码将被执行。
请查看此链接以更清楚: generator function as observer