只為那句承諾-大話Promise

大家周末好凡伊,要說最近幾年什么語言大紅大紫唧席,當屬JavaScript了擦盾。話說雖然是10天就創(chuàng)造出的語言,但是人家能文能武淌哟。web前端自然不必多說了迹卢,各種框架你方登罷我上場,前兩年還是Angular一統(tǒng)天下徒仓,這兩年React又是大紅大紫腐碱,還有Vue最近異軍突起,好不紅火掉弛。要是僅僅是前端也就算了症见,但是由于Node.js人家在后臺也能寫,React Native的出現(xiàn)讓人家移動端也能做殃饿。好吧谋作,還有硬件上也出現(xiàn)Ruff方案,好像硬件上也能寫了壁晒。真是讓人感覺挺有意思的事情瓷们。

圖表君上邊叨叨了這么多业栅,難道是為JavaScript唱贊歌的嗎秒咐?呵呵,其實并不是碘裕。只是最近因為在用上篇文章介紹的AWS Lambda携取。Lambda現(xiàn)在只支持Java,Node.js,Python帮孔。最終選擇了Node.js進行開發(fā)雷滋,不可避免的要牽扯到異步操作的問題不撑。那么今天就來聊聊JavaScript中的Promise。

什么是Promise

Promise是異步編程的一種解決方案晤斩,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大焕檬。它由社區(qū)最早提出和實現(xiàn),ES6將其寫進了語言標準澳泵,統(tǒng)一了用法实愚,原生提供了Promise對象。

所謂Promise兔辅,簡單說就是一個容器腊敲,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說维苔,Promise是一個對象碰辅,從它可以獲取異步操作的消息。Promise提供統(tǒng)一的API介时,各種異步操作都可以用同樣的方法進行處理没宾。

上面是Promise的一個定義,引自阮一峰的ES6標準入門一書潮尝。S6標準入門榕吼。多說一句,目前的JavaScript項目無論是前臺或者是后臺勉失,都應該采用ES6的標準語法來寫羹蚣,ES6讓JavaScript的書寫更加的清晰和規(guī)范。

基本用法

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

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

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

上面的例子給出了new一個promise對象的方法,Promise的構造函數(shù)接受一個函數(shù)作為參數(shù)傳入徒蟆,這個函數(shù)的兩個參數(shù)胁出,reject和resolve是JavaScript本身提供的兩個函數(shù)。
一個promise對象有三個狀態(tài)分別是段审,pending全蝶,resolved,rejected寺枉。resolve函數(shù)可以將pending狀態(tài)轉變?yōu)閞esolved狀態(tài)抑淫。reject函數(shù)可以講pending狀態(tài)轉變了rejected狀態(tài)。對象的狀態(tài)不受外界的影響姥闪,同樣也是promise名字的由來始苇。外部你拿著我的一個承諾,一會我會告訴你我的狀態(tài)筐喳。

promise對象通過then方法來添加回調(diào)函數(shù)催式。例如這樣

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

當promise被resolved的時候函喉,就會把data log出來。當promise被rejected的時候荣月,err就會被log出來管呵。
看上去好像是挺簡單的,的確Promise的應用使得異步的操作哺窄,以同步的形式表現(xiàn)出來撇寞。當發(fā)生錯誤的時候可以通過catch方法,來定義回調(diào)函數(shù)堂氯。

怎么用

上邊都是一些干巴巴的定義蔑担,那么到底該怎么用呢?Promise又怎么樣的解決了問題呢咽白,下邊我們看一個例子啤握。假設下邊一個場景,我們一個服務晶框,從一個外邊service獲取數(shù)據(jù)排抬,然后寫到一個db里,或者一個存儲里授段,最后在把存儲的狀態(tài)龍出來蹲蒲,那么如果沒有promise是怎么寫的呢?可能會是這樣侵贵。

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

傳統(tǒng)的回調(diào)的寫法届搁,這樣使得代碼邏輯混亂在一起。再想想如果再加上錯誤處理的情況窍育,更是酸爽卡睦。那么用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出來。代碼的邏輯以同步的方式得到了體現(xiàn)仪或。我們來看看如果是其他語言會怎么寫确镊,下邊是個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的執(zhí)行環(huán)境是單線程的敦间,所以大量采用了異步的方式來進行編程瓶逃,這使得我們寫起代碼并不十分符合我們一般的習慣束铭。但是Promise的出現(xiàn)讓這種問題能得到一定程度的緩解。

但是異步操作異步操作的好處厢绝,比如上邊的那個例子契沫,如果我們想要做的同時并發(fā)10個操作,那個在ruby或者其他語言中中就要啟多個線程來進行昔汉。但是JavaScript就完全沒有這個問題懈万。只要簡單的loop下就行了。

但是如果我們想要在這10個操作完成后根據(jù)返回的狀態(tài)做點其他操作該怎么做呢靶病?這時候用Promise.all就是最好的了会通。

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

Promise.all接受數(shù)組作為參數(shù)傳入,每個元素都是一個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之間并沒有順序執(zhí)行端三,實際上是并發(fā)的。那么如何讓這些promise是順序執(zhí)行呢鹃彻?留個大家自己思考下郊闯,下篇文章,我們揭曉蛛株⌒樾觯或者可以聯(lián)系圖表君,私下告訴你答案哦泳挥。

ps然痊,當然也可以用一些第三方的庫和方案,例如(async)來實現(xiàn)順序操作屉符,但是代碼的樂趣不就是做些思維挑戰(zhàn)嗎:)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剧浸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子矗钟,更是在濱河造成了極大的恐慌唆香,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吨艇,死亡現(xiàn)場離奇詭異躬它,居然都是意外死亡,警方通過查閱死者的電腦和手機东涡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門冯吓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倘待,“玉大人,你說我怎么就攤上這事组贺⊥苟妫” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵失尖,是天一觀的道長啊奄。 經(jīng)常有香客問我,道長掀潮,這世上最難降的妖魔是什么菇夸? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮仪吧,結果婚禮上峻仇,老公的妹妹穿的比我還像新娘。我一直安慰自己邑商,他們只是感情好摄咆,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著人断,像睡著了一般吭从。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恶迈,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天涩金,我揣著相機與錄音,去河邊找鬼暇仲。 笑死步做,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的奈附。 我是一名探鬼主播全度,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斥滤!你這毒婦竟也來了将鸵?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤佑颇,失蹤者是張志新(化名)和其女友劉穎顶掉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挑胸,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡痒筒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片簿透。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡移袍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萎战,到底是詐尸還是另有隱情,我是刑警寧澤舆逃,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布蚂维,位于F島的核電站,受9級特大地震影響路狮,放射性物質(zhì)發(fā)生泄漏虫啥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一奄妨、第九天 我趴在偏房一處隱蔽的房頂上張望涂籽。 院中可真熱鬧,春花似錦砸抛、人聲如沸评雌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽景东。三九已至,卻和暖如春奔誓,著一層夾襖步出監(jiān)牢的瞬間斤吐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工厨喂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留和措,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓蜕煌,卻偏偏與公主長得像派阱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斜纪,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 00傀广、前言Promise 是異步編程的一種解決方案颁独,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。它由社區(qū)...
    夜幕小草閱讀 2,129評論 0 12
  • Promise的含義: ??Promise是異步編程的一種解決方案伪冰,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,167評論 0 16
  • Promiese 簡單說就是一個容器誓酒,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,語法上說,Pr...
    雨飛飛雨閱讀 3,352評論 0 19
  • JavaScript里通常不建議阻塞主程序靠柑,尤其是一些代價比較昂貴的操作寨辩,如查找數(shù)據(jù)庫,下載文件等操作歼冰,應該用異步...
    張歆琳閱讀 2,752評論 0 12
  • 1)設置盒子與盒子之間的距離margin-bottom: 10px; 2)特點-->當兩個盒子垂直顯示的時候(水平...
    huhu502閱讀 346評論 0 0