煮茶叶
//煮开水
var boilWater = function (cb) {
setTimeout(function(){
cb('boiledWater');
}, 10*60*1000); //10分钟
};
//洗杯子
var washGlass = function(cb) {
setTimeout(function(){
cb('cleanGlass');
}, 2*60*1000); //2分钟
};
//准备茶叶
var prepareTeaLeaves = function(cb){
setTimeout(fucntion(){
cb('teaLeaves');
}, 1*60*1000); //1分钟
};
回调函数来写:代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。因为多个异步操作形成了强耦合,只要有一个操作需要修改,它的上层回调函数和下层回调函数,可能都要跟着修改。这种情况就称为"回调函数地狱"(callback hell)。
Promise写法:
前面的那几个煮开水,洗杯子,煮茶叶的步骤改成Promise方式:
//煮开水
var boilWater = function () {
return new Promise(function(resolve){
setTimeout(function(){
resolve('boiledWater');
}, 10*60*1000); //10分钟
});
};
然后:
Promise.all([
boilWater(),
washGlass(),
prepareTeaLeaves()
]).then(function(result){
console.log(result);
});
如果希望煮开水,洗杯子,煮茶叶按顺序执行呢?
var result = [];
boilWater()
.then(function(boiledWater){
result.push(boiledWater);
return washGlass();
}).then(function(cleanGlass){
if(cleanGlass === false){return false; }
result.push(cleanGlass);
return prepareTeaLeaves();
}).then(function(teaLeaves){
if(teaLeaves === false){return false; }
result.push(teaLeaves);
console.log(result);
});
回调函数的嵌套变成了链式调用,一眼望去,写了好多then…
Generator写法:
function * gen(){
yield boilWater();
yield washGlass();
yield prepareTeaLeaves();
}
var makeTea = gen();
var boiledWater = makeTea.next();
var claenGlass = makeTea.next();
var teaLeaves = makeTea.next();
这么写看起来没那么绕了,但是每次执行下一个操作都要用next(),要有一个任务运行器,自动执行 Generator 函数才方便。
async/await写法:
var result = await Promise.all([
boilWater(),
washGlass(),
prepareTeaLeaves()
]);
想要按照先后顺序异步执行?
var makeTea = async function (){
var boiledWater = await boilWater();
var cleanGlass = await washGlass();
var teaLeaves = await prepareTeaLeaves();
}
async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里,不暴露给用户,因此代码量最少。
async这么好,为什么平时不都用async写?
根据具体场合选择:因为async/await是ES8的语法,需要工具进行预编,例如babel,如果要兼容旧浏览器,那还要加载pollyfill文件,既笨重又麻烦。