使用Promise 和 $.Deferred 解決js回調地獄

爲了提升頁面加載效率,愈來愈多的項目都在使用js異步加載。那麼若是多個異步加載結果互相依賴,而且嵌套會發生什麼事情?沒錯就是讓人聞風喪膽的回調地獄。下面咱們就用setTimeout方法來模擬異步加載,分別瞭解下ES6中Promise 和 jquery中 Deferred 都是怎麼解決回調地獄的。javascript

首先咱們來看一下正常狀況下異步加載嵌套是什麼樣的,也就是js回調地獄是什麼樣的java

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);
}

若是業務邏輯再複雜一些,代碼直接不能看了。。。jquery

Promise

使用promise.then()鏈式調用,解決回調地獄promise

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 <anonymous>:7:18
    at new Promise (<anonymous>)
    at <anonymous>:5:10
    at <anonymous>

使用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()解決回調地獄spa

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.allcode

$.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
相關文章
相關標籤/搜索