Promise,RAC與高階函數(shù)

1.什么是Promise

所謂 Promise,就是JS的一個(gè)對(duì)象,用來(lái)傳遞異步操作結(jié)果的消息。它代表了某個(gè)未來(lái)才會(huì)知道結(jié)果的事件(通常是一個(gè)異步操作),并且這個(gè)事件提供了統(tǒng)一的 API,用來(lái)對(duì)異步調(diào)用需要的兩種結(jié)果(成功與失敗)進(jìn)行處理。

Promise 使用示例:

1.使用new Promise(fn)創(chuàng)建并得到一個(gè)Promise對(duì)象,Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve方法和reject方法。
2.在 fn 中指定異步等處理
(1) 如果異步操作成功,則用 resolve 方法將 Promise 對(duì)象的狀態(tài),從"未完成" 變?yōu)?成功"(即從 pending 變?yōu)?resolved)。
(2) 如果異步操作失敗,則用 reject 方法將 Promise 對(duì)象的狀態(tài),從"未完成"變?yōu)?失敗"(即從 pending 變?yōu)?rejected)。

3.通過(guò)promise的then方法,對(duì)不同狀態(tài)的promise進(jìn)行處理。

var promise = new Promise(function(resolve, reject) { 
  if (/* 異步操作成功 */){
    resolve(value);
  }  else {     
    reject(error);
  }
});

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

2.使用Promise與正常異步回調(diào)的區(qū)別

在callback的模型里邊,我們假設(shè)需要執(zhí)行一個(gè)異步隊(duì)列,代碼看起來(lái)可能像這樣。

var adminIndex = function(params, callback) {
  storeAdmin.getApiTokens(function(err, tokens){    
    if ( err ) { 
      callback(err); 
      return;
     }
    storeAdmin.getApiServices(function(err, apiServices){
      if ( err ) {
        callback(err); 
        return; 
      }
      storeAdmin.getSocketioServices(function(err, socketioServices){
        if ( err ) { 
          callback(err); 
          return;
         }
        callback(0, {status : true,  data : {api_tokens : tokens,api_services : apiServices,socketio_services : socketioServices}});
      });
  });
});
};

這就是常說(shuō)的回調(diào)金字塔,當(dāng)異步的任務(wù)很多的時(shí)候,維護(hù)大量的callback將是一場(chǎng)災(zāi)難。而Promise則是把類似的異步處理對(duì)象和處理規(guī)則進(jìn)行規(guī)范化, 并采用統(tǒng)一的接口來(lái)編寫(xiě),除promise對(duì)象規(guī)定的方法(這里的 then 或 catch )以外的方法都是不可以使用的, 而不會(huì)像回調(diào)函數(shù)方式那樣可以自己自由的定義回調(diào)函數(shù)的參數(shù),從而必須嚴(yán)格遵守固定、統(tǒng)一的編程方式來(lái)編寫(xiě)代碼。各個(gè)階段拋出的錯(cuò)誤都可以在一個(gè)catch下統(tǒng)一處理,同時(shí)promise的then方法會(huì)返回另一個(gè)promise對(duì)象,以便于形成promise管道,這種返回promise對(duì)象的方式能夠支持開(kāi)發(fā)人員把異步操作串聯(lián)起來(lái),從而避免了回調(diào)金子塔的狀況,達(dá)到一個(gè)"線性編碼、異步執(zhí)行"的效果。

3.用.then 或 .catch 添加promise對(duì)象的處理函數(shù)

(1).Promise 狀態(tài):
Promise存在三個(gè)狀態(tài),分別是Fulfilled、 Rejected、 Pending。其創(chuàng)建后狀態(tài)的初始化值為pending,當(dāng)promise中的異步處理任務(wù)得到結(jié)果后,設(shè)置對(duì)應(yīng)的Promise狀態(tài)。而在使用Promise.resolve方法的時(shí)候,可以認(rèn)為它的作用就是將異步操做返回的結(jié)果填充(Fulfilled)到promise對(duì)象并返回這個(gè)promise對(duì)象。


Promise狀態(tài)

之后根據(jù)promise的不同狀態(tài),使用then方法對(duì)其進(jìn)行相應(yīng)的處理。

asyncFunction().then(function onFulfilled(value) {
      console.log(value);
}, function onRejected(error) {
      console.log(error);
});

(2).Promise catch:
Promise提供then方法加載回調(diào)函數(shù),或者使用catch方法捕捉執(zhí)行過(guò)程中拋出的錯(cuò)誤。

aPromise.then(function taskA(value){
     // task A
}).then(function taskB(vaue){
     throw new Error(’taskB has a bug’);
}).catch(function onRejected(error){
     console.log(error);
});

以上數(shù)據(jù)處理流程相當(dāng)于:

aPromise.then(function taskA(value){
     // task A
}).then(function taskB(vaue){
     throw new Error(’taskB has a bug’);
}).then(undefined, function onRejected(error){
     console.log(error);
});

使用promise中的 .then方法 、 .catch方法創(chuàng)建一個(gè)異步獲取網(wǎng)絡(luò)數(shù)據(jù)的流程
我們可以對(duì)過(guò)程中的匿名函數(shù)進(jìn)行封裝, 大概像這樣: getURL(URL).then(parseJson(response)).then(checkResCode(json)).then(handleResponse(json)).catch(....)。可以發(fā)現(xiàn)這段代碼近乎達(dá)到了自然語(yǔ)言的程度,十分優(yōu)雅。
3.Promise chain:
每次調(diào)用promise的then方法后都會(huì)返回一個(gè)新的promise對(duì)象,通過(guò)這種特性我們可以創(chuàng)建對(duì)應(yīng)的promise chain(類似RAC中的signalOperation, 每個(gè)signal的operation方法都返回一個(gè)signal)。

function taskA() {
     console.log("Task A");
}
function taskB() {
     console.log("Task B");
}
function onRejected(error) {
      console.log("Catch Error: A or B", error);
}
function finalTask() {
     console.log("Final Task");
}
var promise = Promise.resolve();
promise.then(taskA)
            .then(taskB)
            .catch(onRejected)
            .then(finalTask);

對(duì)應(yīng)的流程圖:


4.Promise與RAC的異同

以上的promise處理流程如果使用RAC來(lái)表示的話可以表示成下圖代碼:



RAC的CreateSignal 類似于創(chuàng)建一個(gè)promise;sendNext, sendError 可以看成resolve與reject操作;RAC中的try->try->catch 與 promise中的then->then-> catch相似。從相同的代碼格式我們可以看出,RAC與Promise都是在初始化的時(shí)候,就規(guī)劃好數(shù)據(jù)處理流程,使得代碼更加直觀與優(yōu)雅,當(dāng)然在兩者比較舉例的同時(shí)我們可以排除掉一些不影響宏觀層面上不同點(diǎn),比如:RAC信號(hào)需要被訂閱,而Promise在創(chuàng)建好后即執(zhí)行內(nèi)部代碼等。
除去以上的異同點(diǎn),非常值得關(guān)注的就是RAC與Promise都采用了高階函數(shù)的思想。何為高階函數(shù)?高階函數(shù)是至少滿足以下兩個(gè)條件其中之一的函數(shù):1.接收一個(gè)或多個(gè)函數(shù)作為輸入。2.輸出一個(gè)函數(shù)。(同時(shí)FP下高階函數(shù)都有一個(gè)共性:可以鏈?zhǔn)秸{(diào)用)。比如promise中的then, catch使用了函數(shù)參數(shù), RAC的try, catch使用了block就是很好的例子。再比如swift中提供的filter, reduce 與map等。那么它們使用高階函數(shù)有什么好處呢?能夠?qū)F(xiàn)有的代碼由許多粒度非常小的功能函數(shù)來(lái)組合,如果將粒度縮到足夠小的話,這些小粒度的功能函數(shù)能夠達(dá)到極強(qiáng)的通用性,有通用性就可以對(duì)其進(jìn)行下沉, 使其能夠?yàn)槠渌K使用。最后,原先的信號(hào)流或者數(shù)據(jù)流就會(huì)由大量的小粒度功能函數(shù)構(gòu)成,從而把繁瑣而又乏味的任務(wù)抽象出來(lái),這將使代碼顯的直觀與優(yōu)雅。
修改后的RAC代碼:

修改后的promise代碼:

RAC與Promise還有一個(gè)相同的優(yōu)點(diǎn),縱向加載。在SDK寫(xiě)網(wǎng)絡(luò)接口回調(diào)的時(shí)候,往往我們需要驗(yàn)證各種數(shù)據(jù)的正確性,condition1, condition2, condition3...每個(gè)驗(yàn)證條件都是一個(gè)if-else, 條件一多,if-else的多層嵌套讓人眩暈,不僅不利于它人review,對(duì)于編碼者而言,時(shí)間一久也會(huì)頭大。同時(shí)多層的嵌套也非常容易漏掉拋往上層的錯(cuò)誤通知。這種通過(guò)嵌套if-else的寫(xiě)法稱之為橫向發(fā)展,這樣的代碼很快就會(huì)亂成一團(tuán),無(wú)法管理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 11,107評(píng)論 26 95
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,484評(píng)論 0 19
  • 00、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。它由社區(qū)...
    夜幕小草閱讀 2,217評(píng)論 0 12
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 8,771評(píng)論 0 29
  • 4月2日晚8點(diǎn)天使班畢業(yè)典禮,每人3分鐘。開(kāi)學(xué)典禮我就是上夜班時(shí)聽(tīng)的,因?yàn)榫W(wǎng)絡(luò)信號(hào)不好,聽(tīng)的斷斷續(xù)續(xù),真是一個(gè)...
    韓溪流閱讀 824評(píng)論 3 4

友情鏈接更多精彩內(nèi)容