阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...
爲了保證的可讀性,本文采用意譯而非直譯。javascript
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!html
當你第一次開始使用JavaScript時,它會有點使人沮喪。 你會聽到有些人說JavaScript是同步編程語言,而其餘人則認爲它是異步的。 你會聽到阻塞代碼,非阻塞代碼,事件驅動設計模式,事件生命週期,函數堆棧,事件隊列,冒泡,polyfill,babel,angular,reactJS,vueJS 以及大量其餘工具和庫。 不要煩惱,你不是第一個。 這也有一個術語,它被稱爲 JavaScript 疲勞。前端
JavaScript疲勞: 當人們使用不須要的工具來解決他們沒有的問題時,就會出現JavaScript疲勞
JavaScript是一種同步編程語言。可是因爲回調函數,咱們可使它像異步編程語言同樣工做。vue
JavaScript中的 promise 與現實生活中的承諾很是類似。首先讓咱們看看現實生活中的承諾。java
promise 詞典中的定義:保證某人會作某事或某件事會發生。react
那麼當有人向你承諾時,會發生什麼呢?git
根據經驗,對於JavaScript,我老是閱讀來自MDN Web文檔的文檔。在全部資源中,我認爲它們提供了最簡潔的細節。我閱讀了來自 MDSN Web文檔的promise 介紹,並嘗試了一些代碼來掌握它。github
理解承諾有兩個部分。「建立 promises」 和 「處理 promises」。雖然咱們的大多數代碼一般會迎合其餘庫建立的 promises 的處理,但徹底理解這些 promises 確定會有所幫助。一旦你過了初學階段,理解「創造promises 」一樣重要。chrome
讓咱們看一下建立新promis的語法編程
構造函數接受一個名爲executor 的函數。 此執行函數接受兩個參數 resolve 和 reject,它們f都是函數。 Promise 一般用於更容易處理異步操做或阻塞代碼,其示例包括文件操做,API調用,DB調用,IO調用等。這些異步操做的啓動發生在執行函數中。若是異步操做成功,則經過 promise 的建立者調用resolve 函數返回預期結果,一樣,若是出現意外錯誤,則經過調用 reject 函數傳遞錯誤具體信息。
var keepsHisWord; keepsHisWord = true; promise1 = new Promise(function(resolve, reject) { if (keepsHisWord) { resolve("小智承諾堅持分享好的東西給你們"); } else { reject("我沒有作到!"); } }); console.log(promise1);
因爲該 promise 會當即執行,咱們將沒法檢查該 promise 的初始狀態。所以,讓咱們創造一個須要時間來執行的 promise,最簡單的方法是使用 setTimeOut 函數。
promise2 = new Promise(function(resolve, reject) { setTimeout(function() { resolve({ message: "小智承諾堅持分享好的東西給你們", code: "200" }); }, 10 * 1000); }); console.log(promise2);
上面的代碼只是建立了一個在10秒後無條件執行 promise。 所以,咱們能夠檢查promise 的狀態,直到它被 resolve。
一旦十秒鐘過去,promise 就會執行 resolve。PromiseStatus 和 PromiseValue 都會相應地更新。如你所見,咱們更新了 resolve 函數,以便傳遞 JSON 對象,而不是簡單的字符串。這只是爲了說明咱們也能夠在 resolve 函數中傳遞其餘值。
如今讓咱們看看一個 promise reject的例子。咱們只要修改一下 keepsHisWord:
咱們能夠看到 PromiseStatus 能夠有三個不一樣的值,pending(進行中)、 resolved(已成功) 或 rejected(失敗)。建立 promise 時,PromiseStatus 將處於 pending 狀態,而且 PromiseValue 爲 undefined,直到 promise 被 resolved 或 rejected 爲止。 當 promise 處於 resolved 或 rejected 的狀態時,就稱爲 settled(已定型)。 因此 promise 一般從 pending 態轉換到 settled 狀態。
既然咱們知道 promise 是如何建立的,咱們就能夠看看如何使用或處理 promise。這將與理解 Promise 對象密切相關。
根據 MDN 文檔
Promise 對象表示異步操做的最終完成(或失敗)及其結果值
Promise 對象具備靜態方法和原型方法,Promise 對象中的靜態方法能夠獨立應用,而原型方法須要應用於 Promise對象的實例。記住,普通方法和原型都返回一個 romise,這使得理解事物變得容易得多。
讓咱們首先從原型方法開始,有三種方法。重申一下,記住全部這些方法均可以應用於 Promise 對象的一個實例,而且全部這些方法依次返回一個 Promise。如下全部方法都爲 promise 的不一樣狀態轉換分配處理程序。正如咱們前面看到的,當建立一個 Promise 時,它處於 pending 狀態。Promise 根據是否 fulfilled(已成功)或rejected(已失敗),將運行如下三種方法中的一種或多種。
Promise.prototype.catch(onRejected) Promise.prototype.then(onFulfilled, onRejected) Promise.prototype.finally(onFinally)
下圖顯示了 then 和 .catch 方法的流程。因爲它們返回一個 Promise ,它們能夠再次被鏈式調用。無論 promise 最後的狀態,在執行完t hen 或 catch 指定的回調函數之後,都會執行finally方法指定的回調函數。
這裏有一個小故事。你是一個上學的孩子,你問你的媽媽要一個電話。她說:「這個月底我要買一部手機。」
讓咱們看看,若是承諾在月底執行,JavaScript中會是什麼樣子。
var momsPromise = new Promise(function(resolve, reject) { momsSavings = 20000; priceOfPhone = 60000; if (momsSavings > priceOfPhone) { resolve({ brand: "iphone", model: "6s" }); } else { reject("咱們沒有足夠的儲蓄,讓咱們多存點錢吧。"); } }); momsPromise.then(function(value) { console.log("哇,我獲得這個電話做爲禮物 ", JSON.stringify(value)); }); momsPromise.catch(function(reason) { console.log("媽媽不能給我買電話,由於 ", reason); }); momsPromise.finally(function() { console.log( "無論媽媽能不能給我買個電話,我仍然愛她" ); });
輸出:
若是咱們把媽媽的禮物價值改成20萬美圓,那麼媽媽就能夠給兒子買禮物了。在這種狀況下,輸出將是
接着 then方法的第一個參數是 resolved 狀態的回調函數,第二個參數(可選)是 rejected 狀態的回調函數。因此咱們也能夠這樣寫:
可是爲了代碼的可讀性,我認爲最好將它們分開。
爲了確保咱們能夠在瀏覽器中運行全部這些示例,或者在chrome中運行特定的示例,我要確保咱們的代碼示例中沒有外部依賴關係。
爲了更好地理解進一步的主題,讓咱們建立一個函數,該函數將返回一個 Promise,函數裏隨機執行 resolve 或者 rejected ,以便咱們能夠測試各類場景。
因爲咱們須要隨機數,讓咱們先建立一個隨機函數,它將返回x和y之間的隨機數。
讓咱們建立一個函數,它將爲咱們返回 promise。讓咱們調用 promiseTRRARNOSG 函數,它是promiseThatResolvesRandomlyAfterRandomNumnberOfSecondsGenerator 的別名。這個函數將建立一個 promise,該 promise 將在 2 到 10 秒之間的隨機數秒後執行 resolve 或 reject。爲了隨機執行resolve 和 reject,咱們將建立一個介於 1 和 10 之間的隨機數。若是生成的隨機數大於 5,咱們將執行 resolve ,不然執行 reject。
function getRandomNumber(start = 1, end = 10) { //works when both start and end are >=1 return (parseInt(Math.random() * end) % (end - start + 1)) + start; } var promiseTRRARNOSG = (promiseThatResolvesRandomlyAfterRandomNumnberOfSecondsGenerator = function() { return new Promise(function(resolve, reject) { let randomNumberOfSeconds = getRandomNumber(2, 10); setTimeout(function() { let randomiseResolving = getRandomNumber(1, 10); if (randomiseResolving > 5) { resolve({ randomNumberOfSeconds: randomNumberOfSeconds, randomiseResolving: randomiseResolving }); } else { reject({ randomNumberOfSeconds: randomNumberOfSeconds, randomiseResolving: randomiseResolving }); } }, randomNumberOfSeconds * 1000); }); }); var testProimse = promiseTRRARNOSG(); testProimse.then(function(value) { console.log("Value when promise is resolved : ", value); }); testProimse.catch(function(reason) { console.log("Reason when promise is rejected : ", reason); }); // 建立10個不一樣的promise for (i=1; i<=10; i++) { let promise = promiseTRRARNOSG(); promise.then(function(value) { console.log("Value when promise is resolved : ", value); }); promise.catch(function(reason) { console.log("Reason when promise is rejected : ", reason); }); }
刷新瀏覽器頁面並在控制檯中運行代碼,以查看resolve 和 reject 場景的不一樣輸出。
Promise對象中有四種靜態方法。
前兩個是幫助方法或快捷方式。 它們能夠幫助您輕鬆建立 resolved 和 reject 方法。
Promise.reject(reason)
粟子:
Promise.resolve(value)
粟子:
在旁註上,promise 能夠有多個處理程序。所以,你能夠將上述代碼更新爲:
輸出:
下面兩個方法幫助你處理一組 promise 。當你處理多個promise 時,最好先建立一個promise 數組,而後對這些promise 集執行必要的操做。
爲了理解這些方法,咱們不能使用上例中的 promiseTRRARNOSG,由於它太隨機了,最好有一些肯定性的 promise ,這樣咱們才能更好理解 promise 行爲。
讓咱們建立兩個函數。一個會在n秒後執行resolve,另外一個會在n秒後執行 reject。
如今讓咱們使用這些幫助函數來理解 Promise.All
根據 MDN 文檔:
Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable 參數內全部的 promise
都「完成(resolved)」或參數中不包含 promise 時回調完成(resolve);若是參數中 promise
有一個失敗(rejected),此實例回調失敗(reject),失敗緣由的是第一個失敗 promise 的結果。
例一:當全部的 promise 都執行完成了,這是最經常使用的場景。
咱們須要從輸出中得出兩個重要的結論:
例二:當數組不是 promise 的時候呢?(我認爲這是最不經常使用的)
輸出:
因爲數組中沒有 promise,所以將執行 promise 中的 resolve。
例一:其中一個 promise 狀態最早爲 resolve 狀態
根據 MDN:
Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p一、p二、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給 p 的回調函數。
全部的 promise 都是並行運行的。第三個 promise 在 2 秒內完成,因此是最早改變的就返回給Promise.race。
例二:其中一個 promise 狀態最早爲 reject 狀態
全部的 promise 都是並行運行的。第四個 promise 在 3 秒內完成,因此是最早改變的就返回給Promise.race。
原文:https://hackernoon.com/unders...
你的點贊是我持續分享好東西的動力,歡迎點贊!
一個笨笨的碼農,個人世界只能終身學習!
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq44924588...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。