標籤:參考 建議 .com 改變 .net alt 恢複 eth data-
描述
譯者注: 看到了一篇非常好的文章,如果你有興趣,可以查看: Promises與Javascript非同步編程 , 裡面對Promises規範和使用情景,好處講的非常好透徹,個人覺得簡單易懂。
既然是用來處理非同步編程的,那麼在瀏覽器端的JS裡,主要是2種: setTimeout 和 Ajax 請求. promise 的使用就很像Ajax請求的成功和失敗回調。
此承諾/延遲(promise/deferred)實現的靈感來自於 Kris Kowal‘s Q CommonJS Promise建議文檔 將承諾(promise) 作為和 非同步執行操作(action)結果對象進行互動的介面,在指定的時間內可能完成也可能不能夠完成(如逾時,錯誤,攔截等等)。
從錯誤處理的角度看,延遲(
deferred )和承諾(
promise ) API 對於非同步編程來說, 和同步編程的 try,catch, 以及throw作用差不多.
[javascript] view plain copy
- // 為了示範的目的,此處我們假設 `$q`, `scope` 以及 `okToGreet` 引用 在當前執行環境中可用
- // (比如他們已經被注入,或者被當做參數傳進來了).
-
- function asyncGreet(name) {
- var deferred = $q.defer();
-
- setTimeout(function() {
- // 因為此function 在未來的事件迴圈中非同步執行,
- // 我們需要把程式碼封裝裝到到一個 $apply 調用中,以便正確的觀察到 model 的改變
- scope.$apply(function() {
- deferred.notify(‘即將問候 ‘ + name + ‘.‘);
-
- if (okToGreet(name)) {
- deferred.resolve(‘你好, ‘ + name + ‘!‘);
- } else {
- deferred.reject(‘拒絕問候 ‘ + name + ‘ .‘);
- }
- });
- }, 1000);
-
- return deferred.promise;
- }
-
- var promise = asyncGreet(‘小漠漠‘);
- promise.then(function(greeting) {
- alert(‘成功: ‘ + greeting);
- }, function(reason) {
- alert(‘失敗鳥: ‘ + reason);
- }, function(update) {
- alert(‘收到通知: ‘ + update);
- });
引人這種額外的複雜性的效果 在起初可能不明顯。 在 promise 和 deferred APIs 進行承諾時好處就看出來了,請參考: https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md
另外 promise api允許那些在傳統的回調( CPS )方法中很難的實現的組合。 更多資訊請查閱
Q文檔 ,特別是 串列與並行的合并一節。
延遲介面 | Deferred API通過調用 $q.defer() 可以構建一個新的 deffered 執行個體。
deffered 對象用來將 Promise 執行個體與 標記任務狀態(執行成功還是不成功)的 API 相關聯。
deffered 對象的方法
- resolve(value) ——傳入 value 解決派生的 promise。 如果 value 是一個通過 $q.reject 構造的拒絕對象(rejection) , 該promise 將被拒絕。
- reject(reason) ——拒絕派生的promise,並提供原因 。 這相當於通過 $q.reject構造的拒絕對象(rejection)作為參數傳遞給 resolve。
- notify(value) ——在 promise 執行的過程中提供狀態更新。 這在 promise 被解決或拒絕之前可能會被多次調用。
deffered 對象的屬性promise – {Promise} —— 與延遲(deferred)相關聯的 promise 對象。
承諾 介面 | Promise API當建立 deferred 執行個體時會建立一個新的 promise 對象,並可以通過 deferred.promise 得到該引用。
promise 對象的目的是在 deferred 任務完成時,允許感興趣的部分取得其執行結果。
promise 對象的方法
- then(successCallback, errorCallback, notifyCallback) ——不管 promise 是被處理還是被拒絕, 一旦結果可用,then 就會儘快地非同步呼叫 成功/錯誤 回呼函數 只要結果是可用的。 調用回呼函數時傳遞單個參數: 結果 或拒絕的理由。 此外,notify 回調可能被調用 0到多次,以提供 提供一個進度指示,之前承諾解決或拒絕。
這個方法 返回一個新的promise 對象, 根據 successCallback , errorCallback的傳回值進行解決或拒絕 。 它還通過 notifyCallback 方法的傳回值進行通知。 promise 不能從notifyCallback方法得到解決或拒絕 。
- catch(errorCallback) —— promise.then(null, errorCallback) 的捷徑
- finally(callback) ——讓你可以觀察到一個 promise 是被執行還是被拒絕, 但這樣做不用修改最後的 value值。 這可以用來做一些釋放資源或者清理無用對象的工作,不管promise 被拒絕還是解決。 更多的資訊請參閱完整文檔規範.
因為在 ES3版本的JavaScript中 finally 是一個保留字關鍵字,不能作為屬性名稱,為了適配 IE8,您需要使用 promise[‘finally‘](callback) 這種形式來調用該方法。
promise 鏈 | Chaining promises因為調用一個 promise 的 then 方法返回一個新的派生 promise執行個體,所以構建promises鏈也是很容易的:
[javascript] view plain copy
- promiseB = promiseA.then(function(result) {
- return result + 1;
- });
-
- // promiseB 將會在處理完 promiseA 之後立刻被處理,
- // 並且其 value值是promiseA的結果增加1
我們可以建立任意長度的promise鏈;因為一個promise可以被另一個promises處理(進一步延遲解決完成時間),所以在promise鏈上的任意一點進行 暫停/延遲解決 都是可行的。 這使得實現功能強大的APIs 成為現實,例如 $http 的響應攔截器。
Kris Kowal‘s Q 與 $q 之間的區別主要區別有兩點:
- Angular中的$q 整合了 ng.$rootScope.Scope Scope模型觀察機制,這意味著對models 的解決或拒絕速度將會更快,避免不必要的瀏覽器重繪(會導致UI閃爍)。
- Q 比 $q擁有更多的功能特性,但帶來的是代碼位元組數的增加。 $q 很輕量級,但包含了一般非同步任務所需的所有重要功能。
測試
[javascript] view plain copy
- it(‘should simulate promise‘, inject(function($q, $rootScope) {
- var deferred = $q.defer();
- var promise = deferred.promise;
- var resolvedValue;
-
- promise.then(function(value) { resolvedValue = value; });
- expect(resolvedValue).toBeUndefined();
-
- // 類比 promise 的 resolving
- deferred.resolve(123);
- // 注意 ‘then‘ function 不是同步調用的.
- // 因為我們想要 promise API 一直是非同步(async),
- // 不管是在同步調用還是非同步呼叫中都是如此.
- expect(resolvedValue).toBeUndefined();
-
- // 使用 $apply()將 promise resolution 傳遞到 ‘then‘ functions .
- $rootScope.$apply();
- expect(resolvedValue).toEqual(123);
- }));
依賴關係 | Dependencies
$rootScope
方法 | Methods
all(promises)結合多個promises為單個promise,在所有輸入的promise都處理之後,組合之後的promise才會處理完成。
- 參數: promises
- 類型: Array.<Promise>/Object.<Promise>
- 描述: promises的數組或者引用
- 返回: Promise 返回單個的 promise,將與一個數組解決/散列值, 每個值對應於在相同的索引/關鍵的承諾 承諾 /散列數組。 如果任何承諾解決排斥,這產生的承諾將被拒絕 拒絕相同的值。
defer()建立一個 遞延 對象代表一個將來完成任務。
- 返回 Deferred 返回一個新執行個體的Deferred。
reject(reason)建立一個指定拒絕原因的promise. 此api應該用於在一個promises鏈中進行拒絕。 如果你正在處理promise 鏈中的最後一個promise,你不需要擔心。
把 deferreds/promises 與我們熟悉的的 try/catch/throw行為進行對比,可以認為 reject 相當於 JavaScript 中的throw 關鍵字。 這也意味著如果你通過一個 promise 的 error回調, “catch”了一個錯誤 ,你想要指明當前的承諾已經執行出錯了,就必須重新拋出一個“附帶了錯誤資訊,拒絕通過的reject” 。
[javascript] view plain copy
- promiseB = promiseA.then(function(result) {
- // success: 此處可以執行某些操作,然後直接使用原有的result,
- // 或者對result進行操作,來處理接下來的promiseB
- return result;
- }, function(reason) {
- // error: handle the error if possible and
- // resolve promiseB with newPromiseOrValue,
- // 否則轉向拒絕 promiseB 的分支
- if (canHandle(reason)) {
- // 處理錯誤和恢複
- return newPromiseOrValue;
- }
- return $q.reject(reason);
- });
- 參數: reason
- 類型: *
- 描述: Constant, message, exception 或代表拒絕原因的 object。
- 返回: Promise 返回一個promise ,已經因為 reason 而被拒絕了 。
when(value)將一個對象(可能是value 或 [第三方]then-able promise) 封裝為一個 $q promise。 這在你不確定所處理的對象是否是一個promise 時是很有用的,有可能該對象來自於一個不被信任的源頭。
- 參數: value
- 類型: *
- 描述: promise 的值
- 返回 Promise 根據傳入的值/或promise 返回一個封裝後的 promise
$q -- AngularJS中的服務(理解)