使用 Promises 編寫更優雅的 JavaScript 代碼


  你可能已經無意中聽說過 Promises,很多人都在討論它,使用它,但你不知道為什么它們如此特別。難道你不能使用回調么?有什么了特別的?在本文中,我們一起來看看 Promises 是什么以及如何使用它們寫出更優雅的 JavaScript 代碼。

您可能感興趣的相關文章

 

Promises 易於閱讀

  比如說我們想從 HipsterJesus 的API中抓取一些數據並將這些數據添加到我們的頁面中。這些 API 的響應數據形式如下:

{  
  "text": "<p>Lorem ipsum...</p>",  
  "params": {  
  "paras": 4,  
  "type": "hipster-latin" 
}}  

  要使用回調的話,我們通常要寫如下形式的東西:

$.getJSON('http://hipsterjesus.com/api/', function(data) {  
  $('body').append(data.text);  
});  

  如果你有 jQuery 的使用經歷,你會認出我們創建了一個 GET 請求並且希望響應內容是 JSON。我們還傳遞了一個回調函數來接受響應的 JSON,以將數據添加到文檔中。

  另外一種書寫方法是使用 getJSON 方法返回的 promise 對象。你可以直接在這個返回對象上綁定一個回調。

var promise = $.getJSON('http://hipsterjesus.com/api/');promise.done(function(data) {  
  $('body').append(data.text);  
});  

  在上面的回調例子中,當響應成功時它將 API 請求的結果添加到文檔中。但當響應失敗是會發生什么呢?我們可以在我們的 promise 上綁定一個失敗處理器。

var promise = $.getJSON('http://hipsterjesus.com/api/');promise.done(function(data) {  
  $('body').append(data.text);});promise.fail(function() {  
  $('body').append('<p>Oh no, something went wrong!</p>');  
});  

  大多數人刪掉了 promise 變量,這樣更簡潔,一眼就能看出代碼的作用。

$.getJSON('http://hipsterjesus.com/api/').done(function(data) {  
  $('body').append(data.text);}).fail(function() {  
  $('body').append('<p>Oh no, something went wrong!</p>');  
});  

  jQuery 也包含一個一直發生的事件處理器,不論請求成功失敗都會被調用。

$.getJSON('http://hipsterjesus.com/api/').done(function(data) {  
  $('body').append(data.text);}).fail(function() {  
  $('body').append('<p>Oh no, something went wrong!</p>');}).always(function() {  
  $('body').append('<p>I promise this will always be added!.</p>');  
});  

  通過使用promise,回調的順序是按預期的。我們能確保正常回調先被調用,然后是失敗回調,最后是一直發生的回調。

更好的 API

  比如說我們想創造一個 HipsterJesus API 的封裝對象。我們會添加一個方法——html,它將來自 API 的 HTML 數據返回。與之前設置一個回調處理器來解析請求不同,我們可以讓方法返回一個 promise 對象。

var hipsterJesus = {  
  html: function() {  
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {  
      return data.text;  
    });  
}};  

  這個做法很酷,這樣我們可以繞過 promise 對象而不必擔心何時或如何解析它的值。任何需要 promise 返回值的代碼只需注冊一個成功響應回調即可。

then方法允許我們修改promise的結果並將其傳遞給鏈中的下一個處理器。這意味現在我們可以這樣使用新的API:

hipsterJesus.html().done(function(html) {  
  $("body").append(html);  
});  

  直到最近,AngularJS 出現了一個殺手級特性,模板可以直接綁定到promise。在Angular的控制器中,像這樣:

$scope.hipsterIpsum = $http.get('http://hipsterjesus.com/api/');  

  這樣,在模板中寫 {{ hipsterIpsum.text }} 就很簡單了。當 promise 解析后,Angular 不需要自動更新視圖。不幸的是 Angular 團隊已經放棄了這一特性。現在,它可以通過調用 $parseProvider.unwrapPromises(true) 來啟用。我希望Angular已經其他框架一直包含此特性(我會一直留意)。

鏈式調用

  Promise 最出彩的部分是你可以將它們串聯起來。比如說我們想添加一個方法到一個返回一段數組的 API。

var hipsterJesus = {  
 
  html: function() {  
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {  
      return data.text;  
    });  
  },  
 
  paragraphs: function() {  
    return this.html().then(function(html) {  
      return html.replace(/<[^>]+>/g, "").split("");  
    });  
  }};  

  我們以上面的方式這種 HTML 方法,我們用它在 paragraphs 方法中。因為promise回調函數的返回值將傳遞給鏈中的下一個回調,我們能夠在通過它們時自由地創建小的、功能性的方法來改變數據。

  我們可以按需求任意次串聯promise。讓我們添加一個。

var hipsterJesus = {  
 
  html: function() {  
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {  
      return data.text;  
    });  
  },  
 
  paragraphs: function() {  
    return this.html().then(function(html) {  
      return html.replace(/<[^>]+>/g, "").split("");  
    });  
  },  
 
  sentences: function() {  
    return this.paragraphs().then(function(paragraphs) {  
      return [].concat.apply([], paragraphs.map(function(paragraph) {  
        return paragraph.split(/. /);  
      }));  
    });  
  }};   

多個調用

  可能 promise 最顯著的特點是調用多個 API 的能力。當使用回調時,如果你需要同時創建兩個API調用時會發生什么呢?你可能會這樣寫:

var firstData = null;var secondData = null;var responseCallback = function() {  
 
  if (!firstData || !secondData)  
    return;  
 
  // do something}$.get("http://example.com/first", function(data) {  
  firstData = data;  
  responseCallback();});$.get("http://example.com/second", function(data) {  
  secondData = data;  
  responseCallback();  
});  

  使用 promise 的話,這就簡單多了:

var firstPromise = $.get("http://example.com/first");  
var secondPromise = $.get("http://example.com/second");  
$.when(firstPromise, secondPromise).done(function(firstData, secondData) {  
  // do something  
});  

  這里我們使用 when 方法,將其綁定到一個供兩個請求都完成時調用的處理器上。

結論

  這就是 Promise。希望你馬上就想到一些可以用 Promise 實現的的可怕的事情。你最喜歡使用它們的方式是什么?在評論中告訴我吧!

  *注:為簡單起見,本文使用了jQuery的延期執行。jQuery 的 Deferred對象 和 Promises/A+的規范 間有細微的差別,這個規范更標准。更多信息,查看 jQuery維基 上的問答。

 

您可能感興趣的相關文章

 

譯文鏈接:使用 Promises 模式編寫更好的 JavaScript 代碼

編譯來源:夢想天空 ◆ 關注前端開發技術 ◆ 分享網頁設計資源

本文來自【夢想天空(http://www.cnblogs.com/lhb25/)】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM