只爲那句承諾-大話Promise

你們週末好,要說最近幾年什麼語言大紅大紫,當屬JavaScript了。話說雖然是10天就創造出的語言,可是人家能文能武。web前端天然沒必要多說了,各類框架你方登罷我上場,前兩年仍是Angular一統天下,這兩年React又是大紅大紫,還有Vue最近異軍突起,好不紅火。要是僅僅是前端也就算了,可是因爲Node.js人家在後臺也能寫,React Native的出現讓人家移動端也能作。好吧,還有硬件上也出現Ruff方案,好像硬件上也能寫了。真是讓人感受挺有意思的事情。前端

圖表君上邊叨叨了這麼多,難道是爲JavaScript唱讚歌的嗎?呵呵,其實並非。只是最近由於在用上篇文章介紹的AWS Lambda。Lambda如今只支持Java,Node.js,Python。最終選擇了Node.js進行開發,不可避免的要牽扯到異步操做的問題。那麼今天就來聊聊JavaScript中的Promise。es6

什麼是Promise

Promise是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6將其寫進了語言標準,統一了用法,原生提供了Promise對象。web

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise是一個對象,從它能夠獲取異步操做的消息。Promise提供統一的API,各類異步操做均可以用一樣的方法進行處理。編程

上面是Promise的一個定義,引自阮一峯的ES6標準入門一書。S6標準入門。多說一句,目前的JavaScript項目不管是前臺或者是後臺,都應該採用ES6的標準語法來寫,ES6讓JavaScript的書寫更加的清晰和規範。數組

基本用法

如何來構造一個promise對象呢?ES6中提供了原生Promise可使用。promise

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

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

上面的例子給出了new一個promise對象的方法,Promise的構造函數接受一個函數做爲參數傳入,這個函數的兩個參數,reject和resolve是JavaScript自己提供的兩個函數。
一個promise對象有三個狀態分別是,pending,resolved,rejected。resolve函數能夠將pending狀態轉變爲resolved狀態。reject函數能夠講pending狀態轉變了rejected狀態。對象的狀態不受外界的影響,一樣也是promise名字的由來。外部你拿着個人一個承諾,一會我會告訴你個人狀態。ruby

promise對象經過then方法來添加回調函數。例如這樣微信

promise.then(data=> console.log(data), err=> console.log(err));

當promise被resolved的時候,就會把data log出來。當promise被rejected的時候,err就會被log出來。
看上去好像是挺簡單的,的確Promise的應用使得異步的操做,以同步的形式表現出來。當發生錯誤的時候能夠經過catch方法,來定義回調函數。併發

怎麼用

上邊都是一些乾巴巴的定義,那麼到底該怎麼用呢?Promise又怎麼樣的解決了問題呢,下邊咱們看一個例子。假設下邊一個場景,咱們一個服務,從一個外邊service獲取數據,而後寫到一個db裏,或者一個存儲裏,最後在把存儲的狀態龍出來,那麼若是沒有promise是怎麼寫的呢?可能會是這樣。框架

getData(function (value1) {
  storeToDb(value1, function(value2) {
    logStore(value2, function(value3) {
      //...
    });
  });
});

傳統的回調的寫法,這樣使得代碼邏輯混亂在一塊兒。再想一想若是再加上錯誤處理的狀況,更是酸爽。那麼用promise來寫會怎麼樣呢?看下邊這樣的代碼

function getData(){
    return new Promise((resolve,reject) =>{
        // ... send request to get data
        
        if(/* get successfully*/){
            resolve(data)
        }else{
            reject(err)
        }
    })
}

function storeData(data){
    return new Promise((resolve,reject)=>{
        // ... store the data
        
        if(/*store successfully*/){
            resolve(data)
        }else{
            reject(err)
        }
    })
}


getData()
    .then(data => storeData(data))
    .then(data => console.log('the process is done',data));
    .catch(err => console.error('there is the err',err));

這樣寫是否是就是很清楚了,先getData,而後再storeData,最後將此次運行的狀況log了出來,其中有任何的問題,在catch中均可以Catch出來。代碼的邏輯以同步的方式獲得了體現。咱們來看看若是是其餘語言會怎麼寫,下邊是個ruby的語言的例子

def get_data 
    // ...send request
    
    if /*get successfully */
        return data
    else
        raise GetDataError
    end
end


def store_data
    // ...save to db
    
    if /*save successfully */
        return data
    else
        raise StoreDataError
    end
end


/*Main Logic*/
begin
    request_data = get_data
    db_data = store_data request_data
    p "here is the store data #{db_data}"
rescue e
    p "here is some errors #{e}"
end

咱們對比兩個例子,能夠看到在使用的Promise後讓JavaScript的異步方式的編程模式更將清楚,也更加讓人容易理解。

因爲JavaScript的執行環境是單線程的,因此大量採用了異步的方式來進行編程,這使得咱們寫起代碼並不十分符合咱們通常的習慣。可是Promise的出現讓這種問題能獲得必定程度的緩解。

可是異步操做異步操做的好處,好比上邊的那個例子,若是咱們想要作的同時併發10個操做,那個在ruby或者其餘語言中中就要啓多個線程來進行。可是JavaScript就徹底沒有這個問題。只要簡單的loop下就好了。

可是若是咱們想要在這10個操做完成後根據返回的狀態作點其餘操做該怎麼作呢?這時候用Promise.all就是最好的了。

let p = Promise.all([p1, p2, p3]);

Promise.all接受數組做爲參數傳入,每一個元素都是一個promise對象。只要全部子promise都resolved之後,p纔會被resolved。只要有一個被rejected,這個p就會被rejected。可是有一點是這些子promise之間並不會有順序的關係。再來看一個例子:

var guid = 0;
function run() {
  guid++;
  var id = guid;
  return new Promise(resolve => {
    setTimeout(function () {
      console.log(id);
      resolve(id);
    }, (Math.random() * 1.5 | 0) * 1000);
  });
}

var promises = Array.from({ length: 10 }, run);
Promise.all(promises)

OUTPUT:

2
3
5
6
7
8
10
1
4
9

從此次的output能夠看到,promise之間並無順序執行,其實是併發的。那麼如何讓這些promise是順序執行呢?留個你們本身思考下,下篇文章,咱們揭曉。或者能夠聯繫圖表君,私下告訴你答案哦。
ps,固然也能夠用一些第三方的庫和方案,例如(async)來實現順序操做,可是代碼的樂趣不就是作些思惟挑戰嗎:)


原創文章,歡迎轉發,但請標明出處。歡迎關注圖表君的公衆號,一塊兒成長。在微信中搜索 「多彩數據」 或者 「Data_Visualization」

圖片描述

相關文章
相關標籤/搜索