JavaScript是单线程的,程序写到哪里执行到哪里。如果一个function里循环,不释放线程的计算时间,就会造成浏览器用户界面的冻结。下面一段代码展示,在foo循环执行时,在没有执行完循环之前,timer不会触发,虽然timer只设置了1毫秒。
setTimeout(function(){
console.log("Hello World");
},1);
function foo() {
// NOTE: don't ever do crazy long-running loops like this
for (var i=0; i<=1E10; i++) {
console.log(i);
}
}
foo();
// 0..1E10
// "Hello World"
ES6引进了yield
,在写function generator的时候,在函数执行是,可以通过yield来放弃当前执行时间,直到当函数再次被调用的时候,从上次yield
执行的位置继续执行函数体。
所以后面这段代码很有意思,它不是像常规函数执行时那样一行行的执行下去,而是要外部某个地方,不停的执行这个函数,它才会每次从上次间断了的yield
的位置执行。
你可以把这段代码copy到浏览器的console里,然后不断地调用foo()
来看效果。
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
var it = foo();
结果应该大概是这样的:
console.log( it.next() ); // { value:2, done:false }
console.log( it.next() ); // { value:3, done:false }
console.log( it.next() ); // { value:4, done:false }
console.log( it.next() ); // { value:5, done:false }
利用这个特性,ES6就很容易实现iterator模式。例如for...of
会迭代对象的iterator来显示内容:
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (var v of foo()) {
console.log( v );
}
// 1 2 3 4 5
console.log( v ); // still `5`, not `6` :(
上述例子都来自这篇文章,感谢他把ES6 generator讲的这么清晰。