Promise API 簡介

来源:https://www.cnblogs.com/wwhhq/archive/2018/01/01/8169020.html
-Advertisement-
Play Games

Promise API 簡介 譯者註: 到處是回調函數,代碼非常臃腫難看, Promise 主要用來解決這種編程方式, 將某些代碼封裝於內部。 Promise 直譯為“承諾”,但一般直接稱為 Promise; 代碼的可讀性非常重要,因為開發人員支出一般比電腦硬體的支出要大很多倍。 雖然同步代碼更容 ...


Promise API 簡介

譯者註: 到處是回調函數,代碼非常臃腫難看, Promise 主要用來解決這種編程方式, 將某些代碼封裝於內部。

Promise 直譯為“承諾”,但一般直接稱為 Promise;

代碼的可讀性非常重要,因為開發人員支出一般比電腦硬體的支出要大很多倍。

雖然同步代碼更容易跟蹤和調試, 但非同步方式卻具有更好的性能與靈活性.
怎樣在同一時刻發起多個請求, 然後分別處理響應結果? Promise 現已成為 JavaScript 中非常重要的一個組成部分, 很多新的API都以 promise 的方式來實現。下麵簡要介紹 promise, 以及相應的 API 和使用示例!

Promises 周邊

XMLHttpRequest 是非同步API, 但不算 Promise 方式。當前使用 Promise 的原生 api 包括:

Promise 會越來越流行,所以前端開發需要快速掌握它們。當然, Node.js 是另一個使用 Promise 的平臺(顯然, Promise 在Node中是一個核心特性)。

測試 promises 可能比你想象的還要容易, 因為 setTimeout 可以用來當作非同步“任務”!

Promise 基本用法

直接使用 new Promise() 構造函數的方式, 應該只用來處理遺留的非同步任務編程, 例如 setTimeout 或者 XMLHttpRequest。 通過 new 關鍵字創建一個新的 Promise 對象, 該對象有 resolve(搞定!) 和 reject(拒絕!) 兩個回調函數:

var p = new Promise(function(resolve, reject) {
    // ... ... 
    // 此處,可以執行某些非同步任務,然後...
    // 在回調中,或者任何地方執行 resolve/reject

    if(/* good condition */) {
        resolve('傳入成果結果信息,如 data');
    }
    else {
        reject('失敗:原因...!');
    }
});

p.then(function(data) { 
    /* do something with the result */
}).catch(function(err) {
    /* error :( */
});

一般是由開發人員根據非同步任務執行的結果,來手動調用 resolve 或者 reject. 一個典型的例子是將 XMLHttpRequest 轉換為基於Promise的任務:

// 本段示例代碼來源於 Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest

function get(url) {
  // 返回一個 promise 對象.
  return new Promise(function(resolve, reject) {
    // 執行常規的 XHR 請求
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
    // Resolve the promise with the response text
    resolve(req.response);
      }
      else {
    // Otherwise reject with the status text
    // which will hopefully be a meaningful error
    reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error("網路出錯"));
    };

    // Make the request
    req.send();
  });
};

// 使用!
get('story.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.error("Failed!", error);
});

有時候在 promise 方法體中不需要執行非同步任務 —— 當然,在有可能會執行非同步任務的情況下, 返回 promise 將是最好的方式, 這樣只需要給定結果處理函數就行。在這種情況下, 不需要使用 new 關鍵字, 直接返回 Promise.resolve() 或者 Promise.reject()即可。例如:

var userCache = {};

function getUserDetail(username) {
  // In both cases, cached or not, a promise will be returned

  if (userCache[username]) {
    // Return a promise without the "new" keyword
    return Promise.resolve(userCache[username]);
  }

  // Use the fetch API to get the information
  // fetch returns a promise
  return fetch('users/' + username + '.json')
    .then(function(result) {
      userCache[username] = result;
      return result;
    })
    .catch(function() {
      throw new Error('Could not find user: ' + username);
    });
};

因為總是會返回 promise, 所以只需要通過 thencatch 方法處理結果即可!

then

每個 promise 實例都有 then 方法, 用來處理執行結果。 第一個 then 方法回調的參數, 就是 resolve() 傳入的那個值:

new Promise(function(resolve, reject) {
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { resolve(10); }, 3000);
})
.then(function(result) {
    console.log(result);
});

// console 輸出的結果:
// 10

then 回調由 promise 的 resolved 觸發。你也可以使用鏈式的 then` 回調方法:

new Promise(function(resolve, reject) { 
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { resolve(10); }, 3000);
})
.then(function(num) { console.log('first then: ', num); return num * 2; })
.then(function(num) { console.log('second then: ', num); return num * 2; })
.then(function(num) { console.log('last then: ', num);});

// console 輸出的結果:
// first then:  10
// second then:  20
// last then:  40

每個 then 收到的結果都是之前那個 then 返回的值。

如果 promise 已經 resolved, 但之後才調用 then 方法, 則立即觸發回調。如果promise被拒絕之後才調用 then, 則回調函數不會被觸發。

catch

當 promise 被拒絕時, catch 回調就會被執行:

new Promise(function(resolve, reject) {
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { reject('Done!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); });

// console 輸出的結果:
// 'catch: Done!'

傳入 reject 方法的參數由你自己決定。一般來說是傳入一個 Error 對象:

reject(Error('Data could not be found'));

Promise.all

想想JavaScript載入器的情形: 有時候會觸發多個非同步交互, 但只在所有請求完成之後才會做出響應。—— 這種情況可以使用 Promise.all 來處理。Promise.all 方法接受一個 promise 數組, 在所有 promises 都搞定之後, 觸發一個回調:

Promise.all([promise1, promise2]).then(function(results) {
    // Both promises resolved
})
.catch(function(error) {
    // One or more promises was rejected
});

Promise.all 的最佳示例是通過fetch同時發起多個 AJAX請求時:

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');

Promise.all([request1, request2]).then(function(results) {
    // Both promises done!
});

你也可以組合使用 fetch 和 Battery 之類的 API ,因為他們都返回 promises:

Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) {
    // Both promises done!
});

當然, 處理拒絕的情況比較複雜。如果某個 promise 被拒絕, 則 catch 將會被第一個拒絕(rejection)所觸發:

var req1 = new Promise(function(resolve, reject) { 
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { resolve('First!'); }, 4000);
});
var req2 = new Promise(function(resolve, reject) { 
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { reject('Second!'); }, 3000);
});
Promise.all([req1, req2]).then(function(results) {
    console.log('Then: ', one);
}).catch(function(err) {
    console.log('Catch: ', err);
});

// From the console:
// Catch: Second!

隨著越來越多的 API 支持 promise, Promise.all 將會變得超級有用。

Promise.race

Promise.race 是一個有趣的函數. 與 Promise.all 相反, 只要某個 priomise 被 resolved 或者 rejected, 就會觸發 Promise.race:

var req1 = new Promise(function(resolve, reject) { 
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { resolve('First!'); }, 8000);
});
var req2 = new Promise(function(resolve, reject) { 
    // 通過 setTimeout 模擬非同步任務
    setTimeout(function() { resolve('Second!'); }, 3000);
});
Promise.race([req1, req2]).then(function(one) {
    console.log('Then: ', one);
}).catch(function(one, two) {
    console.log('Catch: ', one);
});

// From the console:
// Then: Second!

一個案例是請求的資源有 主站資源和備用資源(以防某個不可用)。

改變習慣, 使用 Promise

在過去幾年中 Promise 一直是個熱門話題(如果你是 Dojo Toolkit 用戶,那麼就是已經有10年了), 已經從一個JavaScript框架變成了語言的一個主要成分. 很快你就會看到大多數新的 JavaScript api 都會基於 Promise 的方式來實現……

... 當然這是一件好事! 開發人員能夠避開回調的地獄, 非同步交互也可以像其他變數一樣傳遞. Promise 還需要一段時間來普及, 現在是時候去學習他們了!

本文轉載自:眾成翻譯
譯者:鐵胖子
鏈接:http://www.zcfy.cc/article/351
原文:https://davidwalsh.name/promises


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如上圖,Runtime SDK是什麼東西?居然還有安卓、蘋果手機、Mac、QT的版本? 是不是意味著ArcGIS的編輯數據和空間分析可以通過編程的方法在每個平臺上滿地跑了? 答案是:是,也不是。 1. 與AO/AE的區別 AO是ArcGIS Desktop和ArcGIS Server的底層技術,有C ...
  • 前言:這一期的破解教程,有新的知識內容出現啦! 這一期破解的游戲是找不到之前的關鍵字,怎麼破解呢? 破解成功之後,添加一個Toast彈窗提示由XX破解,這操作該如何實現呢?請往下看~ 鏈接: https://pan.baidu.com/s/1dF8jKdF 密碼: 6666 破解步驟: 1.試玩,找 ...
  • 在那小小的夢的暖閣,我為你收藏起整個季節的煙雨。 ——洛夫《靈河》 本文為讀 lodash 源碼的第四篇,後續文章會更新到這個倉庫中,歡迎 star: "pocket lodash" gitbook也會同步倉庫的更新,gitbook地址: "pocket lodash" 作用與用法 顧名思義,就是要 ...
  • [1]數據結構 [2]創建棧 [3]使用stack類 [4]ES6 [5]應用 ...
  • 最近在工作中碰到了一個問題,原本在IE8,IE9下正常的input表單,在IE10下會出現清除按鈕,即表單右側會出現一個可以清除該表單內容的小叉。由於之前一直沒有相容過IE10,所以我專門搜了下原因。發現,該功能是微軟在IE10上新添加的功能,用於快速清空表單值。 而問題是,工作中使用到的表單控制項以 ...
  • 之前寫完vue項目後,佈置到伺服器,用nginx反向代理後,一開始進去,進各種路由都是沒問題的,但是一旦f5刷新後就會出現一個nginx404的錯誤。 經過翻閱vue文檔後,發現這是vueHistory 模式下的一個問題,需要後臺配置支持。 History 模式是沒有hash鍵,比如/a/b,f5刷 ...
  • 前言 這裡分享一個博主寫的省市區三級菜單聯動插件 — jQuery Citys,此插件中所有省市區數據均為國家行政區劃代碼,保證數據真實可靠,插件可以根據預設地區代碼或地區名稱進行值的初始化操作。 線上演示地址:https://yangyunhe369.github.io/jQuery Citys ...
  • 無限滾動載入最佳實踐 無限滾動(Infinite scrolling),有時候被稱為無盡滾動(endless scrolling),這種技術允許用戶在大量內容上滾動,眼中看不到結束的地方。這種技術很簡單,就是頁面往下滾動的時候保持刷新。 這項技術使用戶在沒有 打斷 和 額外交互 的情況下滾動列表 — ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...