为了提高页面加载效率,越来越多的项目都在使用js异步加载。那么如果多个异步加载结果互相依赖,并且嵌套会发生什么事情?没错就是让人闻风丧胆的回调地狱。下面我们就用setTimeout方法来模拟异步加载,分别了解下ES6中Promise 和jquery中 Deferred 都是怎么解决回调地狱的。
首先我们来看一下正常情况下异步加载嵌套是什么样的,也就是js回调地狱是什么样的
var myfunc = function() {
console.log("start func1");//模拟第一次回调
setTimeout(function() {
console.log("start func2"); //模拟第二次回调
setTimeout(function() {
console.log("start func3"); //模拟第三次回调
setTimeout(function() {
console.log("start func4"); //模拟第四次回调
setTimeout(function(){
console.log("func end")
},2000)
}, 2000);
}, 2000);
}, 2000);
}
如果业务逻辑再复杂一些,代码直接不能看了。。。
Promise
使用promise.then()链式调用,解决回调地狱
new Promise(function(res, rej) {
console.log("start func1");
setTimeout(res, 2000);
}).then(function() {
return new Promise(function(res, rej) {
console.log("start func2");
setTimeout(res, 2000);
})
}).then(function() {
return new Promise(function(res, rej) {
console.log("start func3");
setTimeout(res, 2000);
})
}).then(function() {
return new Promise(function(res, rej) {
console.log("start func4");
setTimeout(res, 2000);
})
})
//执行结果如下
start func1
start func2
start func3
start func4
使用promise.catch()捕获异常
new Promise(function(res, rej) {
console.log("start func1");
setTimeout(res, 2000);
}).then(function() {
return new Promise(function(res, rej) {
console.log("start func2");
console.log(a);
setTimeout(res, 2000);
})
}).catch(function(msg){
console.log(msg);
})
//执行结果如下
start func1
start func2
ReferenceError: a is not defined
at :7:18
at new Promise ()
at :5:10
at
使用promise.all()同步执行多个异步操作
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("func1 success");
}, 2000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("func2 success");
}, 2000);
});
var p3 = new Promise(function (resolve) {
setTimeout(function () {
resolve("func3 success");
}, 2000);
});
Promise.all([p1, p2, p3]).then(function (result) {
console.log(result);
console.log("all func success");
});
//执行结果
["func1 success", "func2 success","func3 success"]
all func success
部分浏览器对promise可能存在兼容性问题,如果发生兼容性问题可以使用$.Deferred
Deferred
deferred.then()解决回调地狱
function func1(){
var def = $.Deferred();
setTimeout(function(){
def.resolve('func1 result');
}, 2000);
return def.promise();
}
function func2(){
var def = $.Deferred();
setTimeout(function(){
def.resolve('func2 result');
}, 2000);
return def.promise();
}
function func3(){
var def = $.Deferred();
setTimeout(function(){
def.resolve('func3 result');
}, 2000);
return def.promise();
}
func1().then(function(data){
console.log(data);
return func2();
}).then(function(data){
console.log(data);
return func3();
}).then(function(data){
console.log(data);
})
//执行结果
func1 result
func2 result
func3 result
$.when同步执行多个异步操作,所有异步操作执行完毕,执行回调函数,功能类似于 promise.all
$.when(func1(), func2(), func3())
.then(function(data1, data2, data3){
console.log('all success');
console.log(data1, data2, data3);
});
//执行结果
all success
func1 success func2 success func3 success