摘要:我們使用關鍵字和提供的和回調函數來創建新的根據異步任務的返回結果,開發者可以在回調函數體的內部手動調用或者。第一個方法的回調函數接收方法里的值當被時,會調用回調方法。如果被,而方法在之后,那回調函數永遠不會被執行。
盡管同步代碼易于追蹤和調試,但異步代碼普遍在性能和靈活性上更具優勢。Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?(這句要怎么翻??)promise和許多基于promise的新的API已經成為JavaScript世界重要的一部分。讓我們來看一下promise的API如何來使用。
Promises in the WildXMLHttpRequest API是異步的但它并沒有用Promises API,現在有一些native APIs正在使用promises:
Battery API(譯者注:這篇文章我也有翻譯)
fetch API(XHR的取代者)
ServiceWorker API(關于這個API的文章正在路上)
promises會變得很流行,所以前端開發者們都應該去學習它。毫無疑問,Node.js是promises另一個重要的平臺(顯然,promises是一個核心語法特性)。
測試 promises 比你想得容易得多,因為 setTimeout 可以模擬你的異步“任務”
Basic Promise Usage構造函數 new Promise() 應該只用于老式的異步任務,比如 setTimeout 或者 XMLHttpRequest。我們使用 new 關鍵字和promise提供的 resolve 和 reject 回調函數來創建新的 promise:
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 :( */ })
根據異步任務的返回結果,開發者可以在回調函數體的內部手動調用 resolve 或者 reject。把 XMLHttpRequest 轉化為基于promise的任務就是一個實際的例子:
// 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); });
Sometimes you don"t need to complete an async tasks within the promise -- if it"s possible that an async action will be taken, however, returning a promise will be best so that you can always count on a promise coming out of a given function.(譯者注:求大家幫忙翻譯。。)這樣你就可以簡單地調用Promise.resolve() 或者 Promise.reject() 而不需要使用 new 關鍵字。舉例說明:
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對象,你總是可以對這個返回值使用then 或者 catch方法。
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
當promise被resolved時,會調用then回調方法。你也可以鏈式調用 then 方法:
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已經被resolved,then方法有一次被調用,那么回調函數立刻執行。如果promise被rejected,而then方法在rejection之后,那回調函數永遠不會被執行。
catch當promise被rejected時,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方法里執行什么內容取決于你。一個常見的模式是發送一個Error到catch方法中:
reject(Error("Data could not be found"));Promise.all
想一下JavaScript loaders:有許多個異步任務被同時觸發,但你只想在它們都完成之后才做出回應---這就是Promise.all的由來。Promise.all方法傳入一個promise的數組,然后在它們全部resolved之后再出發回調函數:
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! });
你可以合并都返回promise的APIs,比如fetch 和 Battery API:
Promise.all([fetch("/users.json"), navigator.getBattery()]).then(function(results) { // Both promises done! });
當然,處理rejection是困難的。如果數組中有任意一個promise被rejected,catch方法就被觸發,并且接收第一個rejection:
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.race
Promise.race是個有趣的方法---不是等待所有的promise被resolved或者rejected,而是只要數組中有一個promise被resolved或者rejected,Promise.race方法就被觸發:
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!
一個很有用的例子就是在有第一資源請求和第二資源請求時可以用Promise.race。
Get Used to Promises在過去的幾年中,promise一直是一個熱點話題(如果你是Dojo Toolkit用戶的話,會是過去的10年間),現在promise已經從JavaScript框架特性的級別變成了JavaScript語言的特性。你將看到會有越來越多的API會基于promise來實現,這是一個很好的事情!開發者們可以避免以前的callback hell,并且異步interactions可以像其他的變量一樣互相傳遞。promise花了很長的時間變成現在的樣子,而現在是應該學習promise的時候了。
譯自 JavaScript Promise API
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78725.html
摘要:前言對于這門語言,其實我更喜歡稱它為,從一開始我們就已經涉及到異步編程,但是多數開發者從來沒有認真思考過自己程序中的異步,到底是怎么實現的,以及為什么會出現。 前言 對于JavaScript這門語言,其實我更喜歡稱它為ECMAScript,從一開始我們就已經涉及到異步編程,但是多數JavaScript開發者從來沒有認真思考過自己程序中的異步,到底是怎么實現的,以及為什么會出現。但是由于...
摘要:取而代之,利用事件循環體系,使用了一種類似語法的工作方式一旦非阻塞的異步操作完成之后,就可以讓開發者分配的回調函數被觸發。第一個嘗試嵌套的回調函數下面是使用嵌套的回調函數的實現方法這可能對于任何使用者來說再熟悉不過了。 寫在文章前 這篇文章翻譯自 ASYNC/AWAIT WILL MAKE YOUR CODE SIMPLER,這是一篇寫于2017年八月的文章,并由某專欄提名為17年十大...
摘要:不少第三方模塊并沒有做到異步調用,卻裝作支持回調,堆棧的風險就更大。我們可以編寫一個高階函數,讓傳入的函數順序執行還是我們之前的例子看起來還是很不錯的,簡潔并且清晰,最終的代碼量也沒有增加。 原文: http://pij.robinqu.me/JavaScript_Core/Functional_JavaScript/Async_Programing_In_JavaScript....
摘要:函數會在之后的某個時刻觸發事件定時器。事件循環中的這樣一次遍歷被稱為一個。執行完畢并出棧。當定時器過期,宿主環境會把回調函數添加至事件循環隊列中,然后,在未來的某個取出并執行該事件。 原文請查閱這里,略有改動。 本系列持續更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現在,我們將會通過回顧單線程環境下編程的弊端及如何克服這些困難以創建令人驚嘆...
閱讀 2971·2021-11-23 10:12
閱讀 2695·2021-11-23 09:51
閱讀 2045·2021-11-15 11:37
閱讀 1378·2019-08-30 15:55
閱讀 1970·2019-08-29 15:40
閱讀 1170·2019-08-28 18:30
閱讀 1653·2019-08-28 18:02
閱讀 2648·2019-08-26 12:00