淺談es6 promise

 

本文是借鑑於ac黃的博客。javascript

接觸es6也有幾個月了,貌似沒有系統的去學習過它,老是用到什麼,查查什麼。今天就說下es6中的promise對象。前端

先說說promise解決了什麼問題?

寫前端的同窗都常常遇到這種問題:在多個接口異步請求數據,而後利用這些數據來進行一系列的操做。通常以下實現:java

$.ajax({
    url: '......',
    success: function (data) {
    //基於data,才能進行下發操做 $.ajax({ url: '......', success: function (data) { // ...... } }); } });

  這樣寫會致使兩個缺點:jquery

  1. 在須要多個操做的時候,會致使多個回調函數嵌套,致使代碼不夠直觀,就是常說的 Callback Helles6

  2. 若是幾個異步操做之間並無先後順序之分(例如不須要前一個請求的結果做爲後一個請求的參數)時,一樣須要等待上一個操做完成再實行下一個操做。ajax

es6中的Promise對象就來解決這個問題。api

何爲Promise對象?數組

一個 Promise 對象能夠理解爲一次將要執行的操做(經常被用於異步操做),使用了 Promise 對象以後能夠用一種鏈式調用的方式來組織代碼,讓代碼更加直觀(解決第1項缺點)。並且因爲 Promise.all 這樣的方法存在,可讓同時執行多個操做變得簡單(解決第2項缺點)。promise

resolve 和 reject

你們能夠用把下方這段代碼貼到瀏覽器開發模式中的console中運行,看看結果。瀏覽器

function helloWorld (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello World!");
        } else {
            reject("Good bye!");
        }
    });
}

helloWorld(true).then(function (message) {
    alert(message);
}, function (error) {
    alert(error);
});  

結果是,瀏覽器彈出 「hello world!」.

上面的代碼實現的功能很是簡單,helloWord 函數接受一個參數,若是爲 true 就打印 "Hello World!",若是爲 false 就打印錯誤的信息。helloWord 函數返回的是一個 Promise 對象。

在 Promise 對象當中有兩個重要方法————resolve 和 reject

resolve 方法可使 Promise 對象的狀態改變成成功,同時傳遞一個參數用於後續成功後的操做,在這個例子當中就是 Hello World! 字符串。

reject 方法則是將 Promise 對象的狀態改變爲失敗,同時將錯誤的信息傳遞到後續錯誤處理的操做。

Promise 對象有三種狀態:

  • Fulfilled 能夠理解爲成功的狀態

  • Rejected 能夠理解爲失敗的狀態

  • Pending 既不是 Fulfilld 也不是 Rejected 的狀態,能夠理解爲 Promise 對象實例建立時候的初始狀態

helloWorld 的例子中的 then 方法就是根據 Promise 對象的狀態來肯定執行的操做,resolve 時執行第一個函數(onFulfilled),reject 時執行第二個函數(onRejected)。

then 和 catch

then  

helloWorld 的例子當中利用了 then(onFulfilld, onRejected) 方法來執行一個任務打印 "Hello World!",在多個任務的狀況下 then方法一樣能夠用一個清晰的方式完成。

例如:

function printHello (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello");
        } else {
            reject("Good bye!");
        }
    });
}

function printWorld () {
    alert("World");
}

function printExclamation () {
    alert("!");
}

printHello(true)
    .then(function(message){
        alert(message);
    })
    .then(printWorld)
    .then(printExclamation);

  結果是順序彈出:「Hello」「World」「!」

then 可使用鏈式調用的寫法緣由在於,每一次執行該方法時老是會返回一個 Promise 對象。另外,在 then onFulfilled 的函數當中的返回值,能夠做爲後續操做的參數。所以上面的方法能夠寫爲:

function printHello (ready) {
    return new Promise(function (resolve, reject) {
        if (ready) {
            resolve("Hello");
        } else {
            reject("Good bye!");
        }
    });
}

printHello(true).then(function (message) {
    return message;
}).then(function (message) {
    return message  + ' World';
}).then(function (message) {
    return message + '!';
}).then(function (message) {
    alert(message);
});

  結果輸出是:「Hello World!」。

catch

catch 方法是 then(onFulfilled, onRejected) 方法當中 onRejected 函數的一個簡單的寫法,也就是說能夠寫成 then(fn).catch(fn),至關於 then(fn).then(null, fn)。使用 catch 的寫法比通常的寫法更加清晰明確。

Promise.all 和 Promise.race

Promise.all 能夠接收一個元素爲 Promise 對象的數組做爲參數,當這個數組裏面全部的 Promise 對象都變爲 resolve 時,該方法纔會返回。

var p1 = new Promise(function (resolve) {
    setTimeout(function () {
        resolve("Hello");
    }, 3000);
});

var p2 = new Promise(function (resolve) {
    setTimeout(function () {
        resolve("World");
    }, 1000);
});

Promise.all([p1, p2]).then(function (result) {
    console.log(result); // ["Hello", "World"]
});

  

上面的例子模擬了傳輸兩個數據須要不一樣的時長,雖然 p2 的速度比 p1 要快,可是 Promise.all 方法會按照數組裏面的順序將結果返回。

平常開發中常常會遇到這樣的需求,在不一樣的接口請求數據而後拼合成本身所需的數據,一般這些接口之間沒有關聯(例如不須要前一個接口的數據做爲後一個接口的參數),這個時候 Promise.all 方法就能夠派上用場了。

Promise.race 和 Promise.all 方法相似,它一樣接收一個數組,不一樣的是隻要該數組中的 Promise 對象的狀態發生變化(不管是 resolve 仍是 reject)該方法都會返回。

兼容性

在瀏覽器端,一些主流的瀏覽器都已經可使用 Promise 對象進行開發,在 Node.js 配合 babel 也能夠很方便地使用。

若是要兼容舊的瀏覽器,建議能夠尋找一些第三方的解決方案,例如 jQuery 的 $.Deferred

相關文章
相關標籤/搜索