JavaScript Promise API

同步編程一般來講易於調試和維護,然而,異步編程一般能得到更好的性能和更大的靈活性。異步的最大特色是無需等待。「Promises」漸漸成爲JavaScript裏最重要的一部分,大量的新API都開始promise原理實現。下面讓咱們看一下什麼是promise,以及它的API和用法!javascript

Promises現狀

XMLHttpRequest API是異步的,但它沒有使用promise API。但有不少原生的 javascript API 使用了promise:html

Promises未來只會變得愈來愈流行、廣泛,很是重要,全部的前端開發人員都將用到它。另外一個值得注意的是,Node.js是基於Promises的平臺(很顯然,Promise是它的一個核心特徵)。前端

Promises的用法比你想象的要簡單——若是你之前喜歡使用setTimeout來控制異步任務的話!html5

Promise基本用法

new Promise()構造器能夠用在傳統的異步任務中,就像之前 setTimeoutXMLHttpRequest 的用法同樣。一個新的 Promise 使用 new 關鍵字生成,同時,這個 Promises 提供了 resolvereject 函數讓咱們執行回調操做:java

var p = new Promise(function(resolve, reject) { // Do an async task async task and then... if(/* good condition */) { resolve('Success!'); } else { reject('Failure!'); } }); p.then(function() { /* do something with the result */ }).catch(function() { /* error 🙁 */ }) 

程序員能夠手動的在回調函數內部根據執行狀況調用 resolvereject 函數。下面是一個比較具備現實意義的例子,它將一個 XMLHttpRequest 調用轉換爲 基於 Promises 的任務:程序員

// From Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff 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("Network Error")); }; // Make the request req.send(); }); } // Use it! get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.error("Failed!", error); }); 

Promise.resolve()Promise.reject() 能夠直接被調用。有時候,當判斷出 promise 並不須要真正執行時,咱們並不須要 使用 new 建立 Promise 對象,而是能夠直接調用 Promise.resolve()Promise.reject()。好比:es6

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 方法處理返回值!web

then

全部的 promise 對象實例裏都有一個 then 方法,它是用來跟這個 promise 進行交互的。首先,then 方法會缺省調用 resolve() 函數:編程

new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve(10); }, 3000); }) .then(function(result) { console.log(result); }); // From the console: // 10 

then 回調動做的觸發時機是 promise 被執行完。咱們還能夠串聯 then 方法執行回調操做:json

new Promise(function(resolve, reject) { // A mock async action using 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);}); // From the console: // first then: 10 // second then: 20 // last then: 40 

你會發現,每次 then 調用都會以以前的 then 調用的返回值爲參數。

若是一個 promise 已經執行完成,單 then 被再次調用時,回調動做將會被再次執行。而若是這個 promise 裏執行的是reject 回調函數,這是再調用 then 方法,回調函數將不會被執行。

catch

catch 當一個 promise 被拒絕(reject)時,catch 方法會被執行:

new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { reject('Done!'); }, 3000); }) .then(function(e) { console.log('done', e); }) .catch(function(e) { console.log('catch: ', e); }); // From the console: // 'catch: Done!' 

一般咱們在 reject 方法裏處理執行失敗的結果,而在catch 裏執行異常結果:

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

Promise.all

在咱們的異步調用時常常有這樣一種場景:咱們須要同時調用多個異步操做,但但願只有等全部的操做都完成後,咱們纔去執行響應操做——這就是 Promise.all 的做用。 Promise.all 方法能夠接收多個 promise 做爲參數,以數組的形式,當這些 promise 都成功執行完成後才調用回調函數。

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

一個很好的能演示 Promise.all 用法的例子是,執行多個 AJAX 操做(經過 fetch) 調用:

var request1 = fetch('/users.json'); var request2 = fetch('/articles.json'); Promise.all([request1, request2]).then(function(results) { // Both promises done! }); 

咱們還可將fetch電池狀態API混合一塊兒執行,由於它們返回的都是 promise:

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

一旦 promise 裏調用了reject函數,也就是執行被拒絕了,沒有可以正常完成,狀況會有些複雜。一旦 promise 被拒絕,catch 方法會捕捉到首個被執行的reject函數:

var req1 = new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve('First!'); }, 4000); }); var req2 = new Promise(function(resolve, reject) { // A mock async action using 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! 

Promise.all 是很是重要的接口,將會在不少新誕生的 promise API中扮演重要的做用。

Promise.race

Promise.race 是一個有趣的函數——它不是等待全部的 promise 被resolvereject,而是在全部的 promise 中只要有一個執行結束,它就會觸發:

var req1 = new Promise(function(resolve, reject) { // A mock async action using setTimeout setTimeout(function() { resolve('First!'); }, 8000); }); var req2 = new Promise(function(resolve, reject) { // A mock async action using 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! 

一個有用的場景是,從多個鏡像服務器下載資源,一旦有一個返回,其它的返回也就不用處理了。

學會使用 Promises

Promises在過去幾年是一個很是火爆的話題,它甚至從JavaScript裏抽離出來變成了一個語言架構。相信很快咱們將見到有越來越多的JavaScript API將使用以promise爲基礎的模式。

《本文轉自:http://www.webhek.com/javascript-promise-api》

相關文章
相關標籤/搜索