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