一點對Promise的理解與總結


全手打原創,轉載請標明出處:https://www.cnblogs.com/dreamsqin/p/10959411.html,多謝,=。=~ 

 

axios用多了就開始疑惑它里面到底是個啥,雖然總被告知它就是基於ajax的封裝,但掐指一算,事情應該沒這么簡單,於是開始深挖,挖着挖着就挖到了Promise。畢竟axios的官方描述是這樣的:Promise based HTTP client for browser and node.js。而axios其中一個特點就是Supports the Promise API,以前只知道promise是一種替代層層回調的解決方案,但現在看來我認為很有必要詳細的研究一下。

 

背景

在JavaScript的世界中,所有代碼都是單線程執行的。該特性導致JavaScript的所有網絡操作,瀏覽器事件,都必須是異步執行(否則容易發生阻塞)。異步執行可以用回調函數實現,該方式會在將來的某個時間點觸發一個函數調用(回調)。但異步執行中的回調並不利於代碼復用,例如:

request.onreadystatechange = function () {
    if (request.readyState === 4) {
        if (request.status === 200) {
            return success(request.responseText);
        } else {
            return fail(request.status);
        }
    }
}

但如果是這樣的鏈式寫法就會好很多(先統一執行AJAX邏輯,不關心如何處理結果,然后,根據結果是成功還是失敗,在將來的某個時候調用success函數或fail函數):

var ajax = ajaxGet('http://...');
ajax.ifSuccess(success)
    .ifFail(fail);

 

什么是Promise?

上述“承諾將來會執行”的對象在JavaScript中稱為Promise對象,它有各種開源實現,但后面ES6將其寫進了語言標准,統一了用法,原生提供了Promise對象,由瀏覽器直接支持。

Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱Fulfilled)和Rejected(已失敗)。

Promise是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。

ES6規定,Promise對象是一個構造函數,用來生成Promise實例:

var promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve:在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;

reject:在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去;

 

Promise實例生成以后,可以用then方法、catch方法分別指定Resolved狀態和Rejected狀態的回調函數:

// Promise測試(then、catch)
new Promise(function(resolve,reject) {
    let num = Math.random() * 2;
    console.log("產生的隨機數為:" + num);
    setTimeout(function () {
        if(num < 1) {
            console.log("即將執行成功");
            resolve("200 OK");
        } else {
            console.log("即將執行失敗");
            reject("失敗的原因是num為:" + num);
        }
    }, num * 1000);
}).then(function(r) {
    console.log("then:" + r);
}).catch(function(j) {
    console.log("catch:" + j);
});

 

PS:只用then也可以代替上述效果,因為then可以接受兩個回調函數作為參數,第二個參數可選。第一個回調函數是Promise對象的狀態變為Resolved時調用,第二個回調函數是Promise對象的狀態變為Rejected時調用:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

 

鏈式多任務串行

有若干個異步任務,需要先做任務1,如果成功后再做任務2,任何任務失敗則不再繼續並執行錯誤處理函數。要串行執行這樣的異步任務,不用Promise需要寫一層一層的嵌套代碼,而使用Promise則可以采用鏈式寫法:job1.then(job2).then(job3).catch(handleError)

// Promise測試(多任務串行執行)
var p = new Promise(function (resolve, reject) {
    console.log("resolve開始");
    resolve(8);
});

function multi(param) {
    return new Promise(function(resolve, reject) {
        console.log("計算" + param + "*" + param + ":");
        setTimeout(resolve, 1500, param * param);
    });
};

function add(param) {
    return new Promise(function(resolve, reject) {
        console.log("計算" + param + "+" + param + ":");
        setTimeout(resolve, 1500, param + param);
    });
};

p.then(multi).then(add).then(multi).then(function(param){
    console.log("得到最終的值為:" + param);
});

 

Promise.all()實現多任務並行

一個頁面聊天系統,我們需要從兩個不同的URL分別獲得用戶的個人信息和好友列表,這兩個任務是需要並行執行的,用Promise.all()實現如下:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同時執行p1和p2,並在它們都完成后執行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 獲得一個Array: ['P1', 'P2']
});

 

Promise.race()實現多任務賽跑

有些時候,多個異步任務是為了容錯。比如,同時向兩個URL讀取用戶的個人信息,只需要獲得先返回的結果即可,其他任務的結果會被丟棄。這種情況下,用Promise.race()實現:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

 

參考資料

Promise:https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

ECMAScript 6 Promise對象:https://www.w3cschool.cn/ecmascript/3uge1q5v.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM