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