摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯誤,則通過調(diào)用函數(shù)傳遞錯誤具體信息。這將與理解對象密切相關(guān)。這個函數(shù)將創(chuàng)建一個,該將在到秒之間的隨機數(shù)秒后執(zhí)行或。
想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!
背景當(dāng)你第一次開始使用JavaScript時,它會有點令人沮喪。 你會聽到有些人說JavaScript是同步編程語言,而其他人則認為它是異步的。 你會聽到阻塞代碼,非阻塞代碼,事件驅(qū)動設(shè)計模式,事件生命周期,函數(shù)堆棧,事件隊列,冒泡,polyfill,babel,angular,reactJS,vueJS 以及大量其他工具和庫。 不要煩惱,你不是第一個。 這也有一個術(shù)語,它被稱為 JavaScript 疲勞。
JavaScript疲勞: 當(dāng)人們使用不需要的工具來解決他們沒有的問題時,就會出現(xiàn)JavaScript疲勞
JavaScript是一種同步編程語言。但是由于回調(diào)函數(shù),我們可以使它像異步編程語言一樣工作。
初學(xué)者的 PromiseJavaScript中的 promise 與現(xiàn)實生活中的承諾非常相似。首先讓我們看看現(xiàn)實生活中的承諾。
promise 詞典中的定義:保證某人會做某事或某件事會發(fā)生。
那么當(dāng)有人向你承諾時,會發(fā)生什么呢?
承諾給你一個將會有所作為的保證。他們(做出承諾的人)是自己做還是別人做,這無關(guān)緊要。他們給你一個保證,在此基礎(chǔ)上你可以計劃一些事情。
諾言可以遵守,也可以違背。
當(dāng)一個承諾被遵守時,你期望從這個承諾中得到什么。你可以利用承諾的結(jié)果來做進一步的行動或計劃。
當(dāng)一個承諾被打破時,你會想知道為什么做出承諾的人不能履行他的承諾。一旦你知道了原因,并確認承諾已經(jīng)被打破,你就可以計劃下一步要做什么或如何處理它。
在作出承諾的時候,我們所擁有的只是一種保證。我們不能立即采取行動。我們可以決定和制定當(dāng)承諾被遵守(因此我們有了預(yù)期的結(jié)果)或違背(我們知道原因,因此我們可以計劃一個意外事件)時需要做什么。
有可能你根本就沒有收到承諾人的回復(fù)。在這種情況下,您寧愿保留一個時間閾值。如果承諾的人10天后不回來找我,我會認為他有一些問題,不會遵守他的承諾。所以即使那個人在15天后回到你身邊,這對你來說也不再重要,因為你已經(jīng)有了其他的計劃。
JavaScript中的 Promise根據(jù)經(jīng)驗,對于JavaScript,我總是閱讀來自MDN Web文檔的文檔。在所有資源中,我認為它們提供了最簡潔的細節(jié)。我閱讀了來自 MDSN Web文檔的promise 介紹,并嘗試了一些代碼來掌握它。
理解承諾有兩個部分。“創(chuàng)建 promises” 和 “處理 promises”。雖然我們的大多數(shù)代碼通常會迎合其他庫創(chuàng)建的 promises 的處理,但完全理解這些 promises 肯定會有所幫助。一旦你過了初學(xué)階段,理解“創(chuàng)造promises ”同樣重要。
Promise 創(chuàng)建讓我們看一下創(chuàng)建新promis的語法
構(gòu)造函數(shù)接受一個名為executor 的函數(shù)。 此執(zhí)行函數(shù)接受兩個參數(shù) resolve 和 reject,它們f都是函數(shù)。 Promise 通常用于更容易處理異步操作或阻塞代碼,其示例包括文件操作,API調(diào)用,DB調(diào)用,IO調(diào)用等。這些異步操作的啟動發(fā)生在執(zhí)行函數(shù)中。如果異步操作成功,則通過 promise 的創(chuàng)建者調(diào)用resolve 函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯誤,則通過調(diào)用 reject 函數(shù)傳遞錯誤具體信息。
var keepsHisWord; keepsHisWord = true; promise1 = new Promise(function(resolve, reject) { if (keepsHisWord) { resolve("小智承諾堅持分享好的東西給大家"); } else { reject("我沒有做到!"); } }); console.log(promise1);
由于該 promise 會立即執(zhí)行,我們將無法檢查該 promise 的初始狀態(tài)。因此,讓我們創(chuàng)造一個需要時間來執(zhí)行的 promise,最簡單的方法是使用 setTimeOut 函數(shù)。
promise2 = new Promise(function(resolve, reject) { setTimeout(function() { resolve({ message: "小智承諾堅持分享好的東西給大家", code: "200" }); }, 10 * 1000); }); console.log(promise2);
上面的代碼只是創(chuàng)建了一個在10秒后無條件執(zhí)行 promise。 因此,我們可以檢查promise 的狀態(tài),直到它被 resolve。
一旦十秒鐘過去,promise 就會執(zhí)行 resolve。PromiseStatus 和 PromiseValue 都會相應(yīng)地更新。如你所見,我們更新了 resolve 函數(shù),以便傳遞 JSON 對象,而不是簡單的字符串。這只是為了說明我們也可以在 resolve 函數(shù)中傳遞其他值。
現(xiàn)在讓我們看看一個 promise reject的例子。我們只要修改一下 keepsHisWord:
我們可以看到 PromiseStatus 可以有三個不同的值,pending(進行中)、 resolved(已成功) 或 rejected(失敗)。創(chuàng)建 promise 時,PromiseStatus 將處于 pending 狀態(tài),并且 PromiseValue 為 undefined,直到 promise 被 resolved 或 rejected 為止。 當(dāng) promise 處于 resolved 或 rejected 的狀態(tài)時,就稱為 settled(已定型)。 所以 promise 通常從 pending 態(tài)轉(zhuǎn)換到 settled 狀態(tài)。
既然我們知道 promise 是如何創(chuàng)建的,我們就可以看看如何使用或處理 promise。這將與理解 Promise 對象密切相關(guān)。
理解 Promise 對象根據(jù) MDN 文檔
Promise 對象表示異步操作的最終完成(或失敗)及其結(jié)果值
Promise 對象具有靜態(tài)方法和原型方法,Promise 對象中的靜態(tài)方法可以獨立應(yīng)用,而原型方法需要應(yīng)用于 Promise對象的實例。記住,普通方法和原型都返回一個 romise,這使得理解事物變得容易得多。
原型方法(Prototype Methods)讓我們首先從原型方法開始,有三種方法。重申一下,記住所有這些方法都可以應(yīng)用于 Promise 對象的一個實例,并且所有這些方法依次返回一個 Promise。以下所有方法都為 promise 的不同狀態(tài)轉(zhuǎn)換分配處理程序。正如我們前面看到的,當(dāng)創(chuàng)建一個 Promise 時,它處于 pending 狀態(tài)。Promise 根據(jù)是否 fulfilled(已成功)或rejected(已失敗),將運行以下三種方法中的一種或多種。
Promise.prototype.catch(onRejected) Promise.prototype.then(onFulfilled, onRejected) Promise.prototype.finally(onFinally)
下圖顯示了 then 和 .catch 方法的流程。由于它們返回一個 Promise ,它們可以再次被鏈式調(diào)用。不管 promise 最后的狀態(tài),在執(zhí)行完t hen 或 catch 指定的回調(diào)函數(shù)以后,都會執(zhí)行finally方法指定的回調(diào)函數(shù)。
這里有一個小故事。你是一個上學(xué)的孩子,你問你的媽媽要一個電話。她說:“這個月底我要買一部手機。”
讓我們看看,如果承諾在月底執(zhí)行,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方法的第一個參數(shù)是 resolved 狀態(tài)的回調(diào)函數(shù),第二個參數(shù)(可選)是 rejected 狀態(tài)的回調(diào)函數(shù)。所以我們也可以這樣寫:
但是為了代碼的可讀性,我認為最好將它們分開。
為了確保我們可以在瀏覽器中運行所有這些示例,或者在chrome中運行特定的示例,我要確保我們的代碼示例中沒有外部依賴關(guān)系。
為了更好地理解進一步的主題,讓我們創(chuàng)建一個函數(shù),該函數(shù)將返回一個 Promise,函數(shù)里隨機執(zhí)行 resolve 或者 rejected ,以便我們可以測試各種場景。
由于我們需要隨機數(shù),讓我們先創(chuàng)建一個隨機函數(shù),它將返回x和y之間的隨機數(shù)。
讓我們創(chuàng)建一個函數(shù),它將為我們返回 promise。讓我們調(diào)用 promiseTRRARNOSG 函數(shù),它是promiseThatResolvesRandomlyAfterRandomNumnberOfSecondsGenerator 的別名。這個函數(shù)將創(chuàng)建一個 promise,該 promise 將在 2 到 10 秒之間的隨機數(shù)秒后執(zhí)行 resolve 或 reject。為了隨機執(zhí)行resolve 和 reject,我們將創(chuàng)建一個介于 1 和 10 之間的隨機數(shù)。如果生成的隨機數(shù)大于 5,我們將執(zhí)行 resolve ,否則執(zhí)行 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); }); // 創(chuàng)建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 場景的不同輸出。
靜態(tài)方法Promise對象中有四種靜態(tài)方法。
前兩個是幫助方法或快捷方式。 它們可以幫助您輕松創(chuàng)建 resolved 和 reject 方法。
Promise.reject(reason)
粟子:
Promise.resolve(value)
粟子:
在旁注上,promise 可以有多個處理程序。因此,你可以將上述代碼更新為:
輸出:
下面兩個方法幫助你處理一組 promise 。當(dāng)你處理多個promise 時,最好先創(chuàng)建一個promise 數(shù)組,然后對這些promise 集執(zhí)行必要的操作。
為了理解這些方法,我們不能使用上例中的 promiseTRRARNOSG,因為它太隨機了,最好有一些確定性的 promise ,這樣我們才能更好理解 promise 行為。
讓我們創(chuàng)建兩個函數(shù)。一個會在n秒后執(zhí)行resolve,另一個會在n秒后執(zhí)行 reject。
現(xiàn)在讓我們使用這些幫助函數(shù)來理解 Promise.All
Promise.All根據(jù) MDN 文檔:
Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable 參數(shù)內(nèi)所有的 promise
都“完成(resolved)”或參數(shù)中不包含 promise 時回調(diào)完成(resolve);如果參數(shù)中 promise
有一個失敗(rejected),此實例回調(diào)失敗(reject),失敗原因的是第一個失敗 promise 的結(jié)果。
例一:當(dāng)所有的 promise 都執(zhí)行完成了,這是最常用的場景。
我們需要從輸出中得出兩個重要的結(jié)論:
第三個 promise 需要2秒完成,第二個 promise 需要4秒。但是正如你在輸出中看到的,promise
的順序在值中保持不變。
我添加了一個計時器來確定 promise 執(zhí)行所需要時間。如果 promise 是按順序執(zhí)行的,那么總共需要 1+4+2=7 秒,但是從計時器中我們看到它只需要4秒。這證明了所有的 promise 都是并行執(zhí)行的。
例二:當(dāng)數(shù)組不是 promise 的時候呢?(我認為這是最不常用的)
輸出:
由于數(shù)組中沒有 promise,因此將執(zhí)行 promise 中的 resolve。
例一:其中一個 promise 狀態(tài)最先為 resolve 狀態(tài)
Promise.race根據(jù) MDN:
Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給 p 的回調(diào)函數(shù)。
所有的 promise 都是并行運行的。第三個 promise 在 2 秒內(nèi)完成,所以是最先改變的就返回給Promise.race。
例二:其中一個 promise 狀態(tài)最先為 reject 狀態(tài)
所有的 promise 都是并行運行的。第四個 promise 在 3 秒內(nèi)完成,所以是最先改變的就返回給Promise.race。
使用 promise 的經(jīng)驗法則使用異步或阻塞代碼時,請使用 promise。
為了代碼的可讀性,resolve 方法對待 then, reject 對應(yīng) catch 。
確保同時寫入.catch 和 .then 方法來實現(xiàn)所有的 promise。
如果在這兩種情況下都需要做一些事情,請使用 .finally。
我們只有一次改變每個promise (單一原則)。
我們可以在一個promise 中添加多個處理程序。
Promise對象中所有方法的返回類型,無論是靜態(tài)方法還是原型方法,都是Promise。
在Promise.all中,無論哪個promise 首先未完成,promise 的順序都保持在值變量中。
原文:https://hackernoon.com/unders...
你的點贊是我持續(xù)分享好東西的動力,歡迎點贊!
一個笨笨的碼農(nóng),我的世界只能終身學(xué)習(xí)!
交流干貨系列文章匯總?cè)缦拢X得不錯點個Star,歡迎 加群 互相學(xué)習(xí)。
https://github.com/qq44924588...
我是小智,公眾號「大遷世界」作者,對前端技術(shù)保持學(xué)習(xí)愛好者。我會經(jīng)常分享自己所學(xué)所看的干貨,在進階的路上,共勉!
關(guān)注公眾號,后臺回復(fù)福利,即可看到福利,你懂的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/53419.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個符合規(guī)范并可配合使用的寫一個符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個需求:在系統(tǒng)初始化時通過http獲取一個第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個接口,可通過...
摘要:的翻譯文檔由的維護很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯誤,則通過調(diào)用函數(shù)傳遞錯誤具體信息。這將與理解對象密切相關(guān)。這個函數(shù)將創(chuàng)建一個,該將在到秒之間的隨機數(shù)秒后執(zhí)行或。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:主線程會暫時存儲等異步操作,直接向下執(zhí)行,當(dāng)某個異步事件觸發(fā)時,再通知主線程執(zhí)行相應(yīng)的回調(diào)函數(shù),通過這種機制,避免了單線程中異步操作耗時對后續(xù)任務(wù)的影響。 背景 在研究js的異步的實現(xiàn)方式的時候,發(fā)現(xiàn)了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執(zhí)行機制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務(wù)執(zhí)...
摘要:當(dāng)函數(shù)結(jié)束,將會被從調(diào)用棧移出。事件循環(huán)事件循環(huán)的責(zé)任就是查看調(diào)用棧并確定調(diào)用棧是否為空。事件循環(huán)會再次檢查調(diào)用棧是否為空,如果為空的話,它會把事件回調(diào)壓入棧中,然后回調(diào)函數(shù)則被執(zhí)行。 寫在文章前 這篇文章是翻譯自Sukhjinder Arora的Understanding Asynchronous JavaScript。這篇文章描述了異步和同步JavaScript是如何在運行環(huán)境中,...
閱讀 1639·2021-10-09 09:44
閱讀 2787·2021-10-08 10:04
閱讀 2468·2021-09-26 09:55
閱讀 3840·2021-09-22 10:02
閱讀 3311·2019-08-29 17:08
閱讀 1069·2019-08-29 15:08
閱讀 2957·2019-08-26 13:52
閱讀 3274·2019-08-26 13:34