學會Promise,看這裏!!!

前言

衆所周知,在JavaScript的世界中,代碼都是單線程執行的。由於這個原因,JavaScript中的耗時操作,如網絡操作、瀏覽器事件等,都需要異步執行。這也導致在JavaScript中異步操作是非常頻繁且常見的。

異步:在執行某些耗時、不會立即返回結果的操作時,不會阻塞後面的操作,一旦該耗時操作完成時,立即通知需要調用其結果的函數來做後續處理。

而這種通知需要調用其結果的函數來做後續處理,一般都是通過回調的方式實現的。但是爲了實現某些邏輯經常會寫出層層嵌套的回調函數,如果嵌套過多,會極大影響代碼可讀性和邏輯,就會出現”回調地獄“。比如說你要把一個函數 A作爲回調函數,但是該函數又接受一個函數B作爲參數,甚至B還接受C作爲參數使用,就這樣層層嵌套,人稱之爲回調地獄,代碼閱讀性非常差。比如:

var sayhello = function (name, callback) {
  setTimeout(function () {
    console.log(name);
    callback();
  }, 1000);
}

sayhello("first", function () {
  sayhello("second", function () {
    sayhello("third", function () {
      console.log("end");
    });
  });
});

//輸出: first second third  end

而Promise作爲一種可以優雅的解決這種”回調地獄“問題的方案,在實際開發中大面積使用,具有非常不錯的效果。平時開發中,自己也經常看到這種情況,但是每次都是按照模板套路去編寫業務代碼,至於Promise是怎麼使用的,根本沒有學習總結過,導致自己總是一頭霧水。這次,就認真的總結一下,同樣的,只看樣式,不究原理。待日後武義精益了,再來深挖掘。

Promise簡介

Promise是異步編程的一種解決方案,是一個對象,可以獲取異步操作的消息,大大改善了異步編程的困難,避免了回調地獄,比傳統的解決方案回調函數和事件更合理和更強大。

從語法上講,Promise是一個對象,它可以獲取異步操作的消息。提供了一個統一的API,各種異步操作都可以用同樣的方法進行處理。

首先了解下Promise的幾個要點知識:

  1. 語法上,promise是一個構造函數;功能上,promise對象用來封裝一個異步操作並獲取執行的結果;
  2. 它有三種狀態,pending(打包中,創建promise對象後的狀態)、resolved(成功)、rejected(失敗);
  3. 一個promise對象只能改變一次狀態,成功或者失敗後都會返回結果數據;
  4. 成功的結果數據一般稱爲value,失敗的結果數據爲reason。

Promise的實例有兩個過程:

  1. pending > fulfilled :Resolved
  2. pending > rejected :Rejected

Promise基本用法

創建Promise對象

Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)、rejected(已失敗)。Promise構造函數接收一個函數作爲參數,該函數的兩個參數分別是resolvereject

Promise創建時,會傳給promise一個稱爲excutor執行器的函數。這個excutor我們可以理解爲生產者的生產過程函數。這個函數含有兩個參數resolve和reject,這倆參數也同樣是函數,用來傳遞異步操作的結果。

let promise = new Promise(function(resolve, reject) {
  // executor 
})

重點說明:

  1. 在Promise對象創建時,excutor會立即執行;
  2. 在resolve和reject是JS引擎自動創建的函數,我們無需自己創建,只需將其作爲參數傳入就好。

then()用法

Promise 實例生成以後,可以用 then 爲實例添加狀態改變時的回調函數。then方法可以接收兩個回調函數作爲參數,第一個回調函數是Promise對象的狀態改變爲resoved的調用,第二個回調函數是Promise對象的狀態變爲rejected的調用。其中第二個參數可以省略。

function getData() {
    return new Promise(function(resolve, reject) {
        var obj = {num : 0};
        setTimeout(function(){ // 模擬異步請求
            obj.num = Math.random();
            resolve(obj);
        }, 1000);
    });
}

getData().then(function(obj){
    console.log(obj.num);
});

getData函數返回一個promise實例,使用then爲它指定一個Resolved狀態的回調函數,異步請求中傳給resolve的值,將作爲回調函數中的參數。當異步請求成功之後,回調函數變會執行輸出對應的值。

假設異步請求失敗了怎麼辦? then其實還可以指定第二個可選的參數,即Rejected狀態的回調函數。

getData().then(function(obj){
    console.log(obj.num);
}, function(error){
    console.log(error);
});

catch()用法

在上述例子中,異步請求成功後,第一個回調函數會執行,如果失敗了,第二個回調函數便會執行。

其實我們還可以使用catch指定錯誤時的回調,catch調用其實等同於使用then(undefined, function)。上述代碼和以下代碼是同樣的效果。

getData().then(function(obj){
    console.log(obj.num);
}).catch(e){
    console.log(e);
}

all()用法

all方法可以完成並進行任務,它接收的是一個數組,數組的每一項都是Promise對象。當數組中所有的Promise狀態都達到resolved的時候,all方法的狀態就會變成resolved,如果有一個狀態變成了rejected。那麼all方法的狀態就會變成rejected。

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.all([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 輸出 [1, 2, 3]
});

race()用法

race方法和all一樣,接收的參數是一個每項都是Promise的數組,但是與all不同的是,當最先執行完的事件執行完之後,就直接返回該promise對象的值。

race的實際作用:當要做一件事,超過長時間就不做了,可以用這個方法來解決。

let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.race([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 輸出 1
});

finally()用法

finally方法用於指定不管Promise對象最後狀態如何,都會執行的操作。finally方法的回調函數不接受任何參數,這意味着沒有辦法知道前面的Promise狀態到底是fulfilled還是rejected。

總結

由於自己對這個知識點掌握的少,所以這篇文章總結的很基礎,希望對入門的選手有一個幫助。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章