摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創建者調用函數返回預期結果,同樣,如果出現意外錯誤,則通過調用函數傳遞錯誤具體信息。這將與理解對象密切相關。這個函數將創建一個,該將在到秒之間的隨機數秒后執行或。
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!
背景當你第一次開始使用JavaScript時,它會有點令人沮喪。 你會聽到有些人說JavaScript是同步編程語言,而其他人則認為它是異步的。 你會聽到阻塞代碼,非阻塞代碼,事件驅動設計模式,事件生命周期,函數堆棧,事件隊列,冒泡,polyfill,babel,angular,reactJS,vueJS 以及大量其他工具和庫。 不要煩惱,你不是第一個。 這也有一個術語,它被稱為 JavaScript 疲勞。
JavaScript疲勞: 當人們使用不需要的工具來解決他們沒有的問題時,就會出現JavaScript疲勞
JavaScript是一種同步編程語言。但是由于回調函數,我們可以使它像異步編程語言一樣工作。
初學者的 PromiseJavaScript中的 promise 與現實生活中的承諾非常相似。首先讓我們看看現實生活中的承諾。
promise 詞典中的定義:保證某人會做某事或某件事會發生。
那么當有人向你承諾時,會發生什么呢?
承諾給你一個將會有所作為的保證。他們(做出承諾的人)是自己做還是別人做,這無關緊要。他們給你一個保證,在此基礎上你可以計劃一些事情。
諾言可以遵守,也可以違背。
當一個承諾被遵守時,你期望從這個承諾中得到什么。你可以利用承諾的結果來做進一步的行動或計劃。
當一個承諾被打破時,你會想知道為什么做出承諾的人不能履行他的承諾。一旦你知道了原因,并確認承諾已經被打破,你就可以計劃下一步要做什么或如何處理它。
在作出承諾的時候,我們所擁有的只是一種保證。我們不能立即采取行動。我們可以決定和制定當承諾被遵守(因此我們有了預期的結果)或違背(我們知道原因,因此我們可以計劃一個意外事件)時需要做什么。
有可能你根本就沒有收到承諾人的回復。在這種情況下,您寧愿保留一個時間閾值。如果承諾的人10天后不回來找我,我會認為他有一些問題,不會遵守他的承諾。所以即使那個人在15天后回到你身邊,這對你來說也不再重要,因為你已經有了其他的計劃。
JavaScript中的 Promise根據經驗,對于JavaScript,我總是閱讀來自MDN Web文檔的文檔。在所有資源中,我認為它們提供了最簡潔的細節。我閱讀了來自 MDSN Web文檔的promise 介紹,并嘗試了一些代碼來掌握它。
理解承諾有兩個部分。“創建 promises” 和 “處理 promises”。雖然我們的大多數代碼通常會迎合其他庫創建的 promises 的處理,但完全理解這些 promises 肯定會有所幫助。一旦你過了初學階段,理解“創造promises ”同樣重要。
Promise 創建讓我們看一下創建新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 對象密切相關。
理解 Promise 對象根據 MDN 文檔
Promise 對象表示異步操作的最終完成(或失敗)及其結果值
Promise 對象具有靜態方法和原型方法,Promise 對象中的靜態方法可以獨立應用,而原型方法需要應用于 Promise對象的實例。記住,普通方法和原型都返回一個 romise,這使得理解事物變得容易得多。
原型方法(Prototype Methods)讓我們首先從原型方法開始,有三種方法。重申一下,記住所有這些方法都可以應用于 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
Promise.All根據 MDN 文檔:
Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable 參數內所有的 promise
都“完成(resolved)”或參數中不包含 promise 時回調完成(resolve);如果參數中 promise
有一個失敗(rejected),此實例回調失敗(reject),失敗原因的是第一個失敗 promise 的結果。
例一:當所有的 promise 都執行完成了,這是最常用的場景。
我們需要從輸出中得出兩個重要的結論:
第三個 promise 需要2秒完成,第二個 promise 需要4秒。但是正如你在輸出中看到的,promise
的順序在值中保持不變。
我添加了一個計時器來確定 promise 執行所需要時間。如果 promise 是按順序執行的,那么總共需要 1+4+2=7 秒,但是從計時器中我們看到它只需要4秒。這證明了所有的 promise 都是并行執行的。
例二:當數組不是 promise 的時候呢?(我認為這是最不常用的)
輸出:
由于數組中沒有 promise,因此將執行 promise 中的 resolve。
例一:其中一個 promise 狀態最先為 resolve 狀態
Promise.race根據 MDN:
Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給 p 的回調函數。
所有的 promise 都是并行運行的。第三個 promise 在 2 秒內完成,所以是最先改變的就返回給Promise.race。
例二:其中一個 promise 狀態最先為 reject 狀態
所有的 promise 都是并行運行的。第四個 promise 在 3 秒內完成,所以是最先改變的就返回給Promise.race。
使用 promise 的經驗法則使用異步或阻塞代碼時,請使用 promise。
為了代碼的可讀性,resolve 方法對待 then, reject 對應 catch 。
確保同時寫入.catch 和 .then 方法來實現所有的 promise。
如果在這兩種情況下都需要做一些事情,請使用 .finally。
我們只有一次改變每個promise (單一原則)。
我們可以在一個promise 中添加多個處理程序。
Promise對象中所有方法的返回類型,無論是靜態方法還是原型方法,都是Promise。
在Promise.all中,無論哪個promise 首先未完成,promise 的順序都保持在值變量中。
原文:https://hackernoon.com/unders...
你的點贊是我持續分享好東西的動力,歡迎點贊!
一個笨笨的碼農,我的世界只能終身學習!
交流干貨系列文章匯總如下,覺得不錯點個Star,歡迎 加群 互相學習。
https://github.com/qq44924588...
我是小智,公眾號「大遷世界」作者,對前端技術保持學習愛好者。我會經常分享自己所學所看的干貨,在進階的路上,共勉!
關注公眾號,后臺回復福利,即可看到福利,你懂的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99839.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創建者調用函數返回預期結果,同樣,如果出現意外錯誤,則通過調用函數傳遞錯誤具體信息。這將與理解對象密切相關。這個函數將創建一個,該將在到秒之間的隨機數秒后執行或。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:主線程會暫時存儲等異步操作,直接向下執行,當某個異步事件觸發時,再通知主線程執行相應的回調函數,通過這種機制,避免了單線程中異步操作耗時對后續任務的影響。 背景 在研究js的異步的實現方式的時候,發現了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執行機制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務執...
摘要:當函數結束,將會被從調用棧移出。事件循環事件循環的責任就是查看調用棧并確定調用棧是否為空。事件循環會再次檢查調用棧是否為空,如果為空的話,它會把事件回調壓入棧中,然后回調函數則被執行。 寫在文章前 這篇文章是翻譯自Sukhjinder Arora的Understanding Asynchronous JavaScript。這篇文章描述了異步和同步JavaScript是如何在運行環境中,...
閱讀 2413·2021-11-18 10:02
閱讀 1927·2021-10-13 09:40
閱讀 3006·2021-09-07 10:07
閱讀 2114·2021-09-04 16:48
閱讀 1014·2019-08-30 13:18
閱讀 2461·2019-08-29 14:03
閱讀 2927·2019-08-29 12:54
閱讀 3163·2019-08-26 11:41