1.Generator 与 协程
协程是一种程序运行的方式,可以理解为"写作的线程",或者"协作的函数",协程既可以单线程实现,也可以多线程实现;
前者是一种特殊的子例程,后者是一种特殊的线程。
2.Generator应用
Generator 可以暂停函数执行,返回任意表达式的值。这种特点使得Generator有多种应用场景。
3.Generator异步操作的同步化表达
Generator函数的暂停执行效果,意味着可以把异步操作写在yield语句里面。等到调用next方法的时候再往后执行。
这是继上等同于不需要再写回调函数了。
所以Generator函数的一个重要的实际意义就是处理异步操作,改写回调函数。
{
function* loadUI(){
showLodingScreen();
yield loadUIDataAsynchronously();
hideLodingScreen();
}
let loader = loadUI();
//加载UI
loader.next();
//卸载UI
loader.next();
}
上述代码中,第一次调用loadUI函数时候,该函数不会执行,仅返回一个遍历器。下一步对该函数调用next方法,
则会显示Loading页面(showLodingScreen()),并且异步加载数据(loadUIDataAsynchronously)。等到数据加载
完成,再一次调用next方法,则会隐藏loading界面。可以看到,这种写法的好处就是所有Loading页面的逻辑,都被封装到
一个函数中,按部就班非常清晰。
Generator部署AJAX操作
{
function* main(){
let result = yield request("http://some.url");
let resp = JSON.parse(result);
console.log(resp.revalue);
}
function request(url){
makeAjaxCall(url, function(response){
it.next(response);
})
}
let it = main();
it.next();
}
上面的main函数就是用过AJAX操作读取数据。可以看到,除了多一个yield基本与同步操作的写法一样。
4.控制流管理
如果一个多部操作非常耗时,采用回调函数可能会写成下面这样。
{
step1(function(value1){
step2(function (value2){
step3(function (value3){
step4(function (value4){
//do something.
})
})
})
})
}
//采用promise
{
Promise.resolve(step1)
.then(step2)
.then(step3)
.then(step4)
.then(function(value4){
// do something
},function(err){
console.log(err);
})
}
//采用Generator函数
{
function* longRuningTask(value1) {
try {
let value1 = yield step1(value1);
let value2 = yield step1(value2);
let value3 = yield step1(value3);
let value4 = yield step1(value4);
} catch (e) {
//some err msg;
}
}
// 然后使用一个函数按次序自动执行所有步骤
scheduler(longRuningTask(initialValue));
function scheduler(task){
let taskObj = task.next(task.value);
//如果Generator函数未结束,就继续调用
if(!taskObj.done){
task.value = taskObj.value;
scheduler(task);
}
}
}
这种方法只能用于所用同步操作,及所有的task都必须是同步的。
5.部署iterator接口
{
function* iterator(obj) {
let keys = Object.keys(obj);
for(let i=0; i< keys.length; i++){
let key = keys[i];
yield [key,obj[key]];
}
}
let myObj = {foo:3, bar:7};
for(let [key,value] of iterator(myObj)){
console.log(key,value);
}
//foo 3
//bar 7
}
// 上述代码中,myObj是一个普通对象,通过iterator函数就有了Iterator接口。也就是说,可以再任意对象上部署next方法。
- 参考文献<ES6标准入门> 阮一峰著