摘要:使用對(duì)象的好處在于可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套的回調(diào)函數(shù)。對(duì)象異步操作拋出錯(cuò)誤,狀態(tài)就會(huì)變?yōu)椋蜁?huì)調(diào)用方法指定的回調(diào)函數(shù)處理這個(gè)錯(cuò)誤。
Promise 含義
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。它由社區(qū)最早提出和實(shí)現(xiàn),ES6 將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn),統(tǒng)一了用法,原生提供了 Promise 對(duì)象。
所謂 Promise,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō),Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進(jìn)行處理。
Promise 對(duì)象有以下兩個(gè)特點(diǎn):
對(duì)象的狀態(tài)不受外界影響。有三種狀態(tài),分別為 pending(進(jìn)行中)、fulfilled(已成功)和 rejected(已失?。?。
一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。狀態(tài)改變只有兩種可能:從 pending 變?yōu)?fulfilled 和從 pending 變?yōu)?rejected。
使用 Promise 對(duì)象的好處在于:
可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套的回調(diào)函數(shù)。
Promise 對(duì)象提供統(tǒng)一的接口,使得控制異步操作更加容易。
Promise 缺點(diǎn):
無(wú)法取消 Promise,一旦新建它就會(huì)立即執(zhí)行,無(wú)法中途取消。
如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。
當(dāng)處于 pending 狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。
基本用法ES6 規(guī)定,Promise 對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成 Promise 實(shí)例。
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise.then( res => { console.log("成功:" + res); }, err => { console.log("失敗:" + err); } );
Promise 構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是 resolve 和 reject。它們是兩個(gè)函數(shù),由 JavaScript 引擎提供,不用自己部署。
resolve 函數(shù)的作用:將 Promise 對(duì)象的狀態(tài)從“未完成(pending)”變?yōu)椤俺晒Γ╮esolved)”,在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果作為參數(shù)傳遞出去。
reject 函數(shù)的作用:將 Promise 對(duì)象的狀態(tài)從“未完成(pending)”變?yōu)椤笆。╮ejected)”在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。
then 方法作用:接受兩個(gè)回調(diào)函數(shù)作為參數(shù)。第一個(gè)回調(diào)函數(shù)是 Promise 對(duì)象的狀態(tài)變?yōu)?resolved 時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是 Promise 對(duì)象的狀態(tài)變?yōu)?rejected 時(shí)調(diào)用。第二個(gè)函數(shù)可選,不一定要提供,也可以將第二個(gè)函數(shù)作為 catch 方法的參數(shù)。
catch 方法作用:用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。Promise 對(duì)象異步操作拋出錯(cuò)誤,狀態(tài)就會(huì)變?yōu)?rejected,就會(huì)調(diào)用 catch 方法指定的回調(diào)函數(shù)處理這個(gè)錯(cuò)誤。另外,then 方法指定的回調(diào)函數(shù),如果運(yùn)行中拋出錯(cuò)誤,也會(huì)被 catch 方法捕獲。
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise .then(res => { console.log("成功:" + res); }) .catch(err => { console.log("失敗:" + err); }); promise .then(res => { console.log("成功:" + res); throw new Error("test"); }) .catch(err => { // num > 0.5時(shí)打印 "失敗:Error: test" console.log("失敗:" + err); });Promise 執(zhí)行順序
Promise 新建后立即執(zhí)行,then 方法指定的回調(diào)函數(shù),將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會(huì)執(zhí)行,catch 同理。
調(diào)用 resolve 或 reject 并不會(huì)終結(jié) Promise 的參數(shù)函數(shù)的執(zhí)行。
const promise = new Promise((resolve, reject) => { console.log("我是第一個(gè)執(zhí)行的"); resolve(); }); promise.then(res => { console.log("我是第三個(gè)執(zhí)行的"); }); console.log("我是第二個(gè)執(zhí)行的");resolve 函數(shù)和 reject 函數(shù)的參數(shù)
reject 函數(shù)的參數(shù)通常是 Error 對(duì)象的實(shí)例,表示拋出的錯(cuò)誤;resolve 函數(shù)的參數(shù)除了正常的值以外,還可能是另一個(gè) Promise 實(shí)例。
如果一個(gè) Promise(P2) 的 resolve 參數(shù)是另一個(gè) Promise(P1),此時(shí) P1 的狀態(tài)就會(huì)傳給 P2,P1 的狀態(tài)決定了 P2 的狀態(tài),P1 的狀態(tài)改變,P2 的回調(diào)函數(shù)才會(huì)執(zhí)行。
const p1 = new Promise(function(resolve, reject) { setTimeout(() => reject(new Error("fail")), 3000); }); const p2 = new Promise(function(resolve, reject) { setTimeout(() => resolve(p1), 1000); }); p2.then(result => console.log(result)).catch(error => console.log(error)); // Error: fail
上面代碼中,p1 是一個(gè) Promise,3 秒之后變?yōu)?rejected。p2 的狀態(tài)在 1 秒之后改變,resolve 方法返回的是 p1。由于 p2 返回的是另一個(gè) Promise,導(dǎo)致 p2 自己的狀態(tài)無(wú)效了,由 p1 的狀態(tài)決定 p2 的狀態(tài)。所以,后面的 then 語(yǔ)句都變成針對(duì)后者(p1)。又過(guò)了 2 秒,p1 變?yōu)?rejected,導(dǎo)致觸發(fā) catch 方法指定的回調(diào)函數(shù)。
Promise 鏈?zhǔn)秸{(diào)用then 方法可以返回一個(gè)新的 Promise 實(shí)例(注意,不是原來(lái)那個(gè) Promise 實(shí)例)。因此可以采用鏈?zhǔn)綄懛?,?then 方法后面再調(diào)用另一個(gè) then 方法。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return "promise1"; }) .then(res => { console.log(res); // promise1 return "promise2"; }) .then(res => { console.log(res); // promise2 });
注意:只要一個(gè) Promise 中拋出錯(cuò)誤,將執(zhí)行 catch 方法,then 鏈終止。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise throw new Error("中止"); return "promise1"; }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { console.log(err); // Error: 中止 });
主動(dòng)終止 then 鏈,通過(guò) catch 方法來(lái)中止 promise chain
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return Promise.reject({ notRealPromiseException: true }); }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { if (err.notRealPromiseException) { return true; } console.log(err); });Promise.prototype.finally()
finally 方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的操作。該方法是 ES2018 引入標(biāo)準(zhǔn)的。
finally 本質(zhì)上是 then 方法的特例,不接受任何參數(shù),不依賴于 Promise 的執(zhí)行結(jié)果
promise.finally(() => { // 語(yǔ)句 }); // 等同于 promise.then( result => { // 語(yǔ)句 return result; }, error => { // 語(yǔ)句 throw error; } );Promise.all()
Promise.all 方法用于將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。
const promise = Promise.all([promise1, promise2, promise3])
Promise.all 方法接受一個(gè)數(shù)組作為參數(shù),promise、pro 米色、promise3 都是 Promise 實(shí)例,如果不是,就會(huì)先調(diào)用下面講到的 Promise.resolve 方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。(Promise.all 方法的參數(shù)可以不是數(shù)組,但必須具有 Iterator 接口,且返回的每個(gè)成員都是 Promise 實(shí)例。了解 Iterator 接口)
promise 的狀態(tài)由 promise1、promise2、promise3 決定,分成兩種情況。
只有 promise1、promise2、promise3 的狀態(tài)都變成 fulfilled,p 的狀態(tài)才會(huì)變成 fulfilled,此時(shí) promise1、promise2、promise3 的返回值組成一個(gè)數(shù)組,傳遞給 p 的回調(diào)函數(shù)。
只要 promise1、promise2、promise3 之中有一個(gè)被 rejected,promise 的狀態(tài)就變成 rejected,此時(shí)第一個(gè)被 reject 的實(shí)例的返回值,會(huì)傳遞給 promise 的回調(diào)函數(shù)。
const p1 = new Promise((resolve, reject) => { resolve("hello"); }) .then(result => result) .catch(e => e); const p2 = new Promise((resolve, reject) => { throw new Error("報(bào)錯(cuò)了"); }) .then(result => result) .catch(e => e); Promise.all([p1, p2]) .then(result => console.log(result)) .catch(e => console.log(e)); // ["hello", Error: 報(bào)錯(cuò)了]
上面代碼中,p1 會(huì) resolved,p2 首先會(huì) rejected,但是 p2 有自己的 catch 方法,該方法返回的是一個(gè)新的 Promise 實(shí)例,p2 指向的實(shí)際上是這個(gè)實(shí)例。該實(shí)例執(zhí)行完 catch 方法后,也會(huì)變成 resolved,導(dǎo)致 Promise.all()方法參數(shù)里面的兩個(gè)實(shí)例都會(huì) resolved,因此會(huì)調(diào)用 then 方法指定的回調(diào)函數(shù),而不會(huì)調(diào)用 catch 方法指定的回調(diào)函數(shù)。
如果 p2 沒(méi)有自己的 catch 方法,就會(huì)調(diào)用 Promise.all()的 catch 方法。
Promise.race()Promise.race 方法同樣是將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。
const p = Promise.race([p1, p2, p3])
只要 p1、p2、p3 之中有一個(gè)實(shí)例率先改變狀態(tài),p 的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給 p 的回調(diào)函數(shù)。
Promise.race 方法的參數(shù)與 Promise.all 方法一樣,如果不是 Promise 實(shí)例,就會(huì)先調(diào)用下面講到的 Promise.resolve 方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。
Promise.resolve()將現(xiàn)有對(duì)象轉(zhuǎn)化為 Promise 對(duì)象。
const promise = Promise.resolve("Hello world")
參數(shù)是 Promise 實(shí)例,該方法不做任何改變。
參數(shù)是一個(gè) thenable 對(duì)象,先將對(duì)象轉(zhuǎn)為 Promise 對(duì)象,然后立即執(zhí)行 thenable 方法。相當(dāng)于將 thenable 對(duì)象中的 then 方法處理的值作為參數(shù)傳給 promise then 方法。
let thenObj = { then(resolve, reject) { resolve("Hello"); } }; const promise = Promise.resolve(thenObj); promise.then(res => { console.log(res); // Hello });
參數(shù)不是具有 then 方法的對(duì)象,或根本就不是對(duì)象,則 Promise.resolve 方法返回一個(gè)新的 Promise 對(duì)象,狀態(tài)為 resolved。
Promise.reject()Promise.reject(reason)方法也會(huì)返回一個(gè)新的 Promise 實(shí)例,該實(shí)例的狀態(tài)為 rejected。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103253.html
摘要:中就是一個(gè)構(gòu)造函數(shù)函數(shù)也是對(duì)象為什么需要多個(gè)嵌套的異步操作,如果直接用方式,會(huì)導(dǎo)致的出現(xiàn)使得異步操作更加規(guī)范,更加統(tǒng)一。的方法構(gòu)造函數(shù)構(gòu)造函數(shù)用于生成對(duì)象,函數(shù)在構(gòu)造函數(shù)執(zhí)行時(shí)同步執(zhí)行。 什么是Promise? 含以上:抽象異步操作的工具。javascript中:Promise就是一個(gè)構(gòu)造函數(shù)(函數(shù)也是對(duì)象) 為什么需要Promise? 1.多個(gè)嵌套的異步操作,如果直接用callbac...
摘要:從最開始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
摘要:在異步編程中,提供了對(duì)象的方式。例如等同于所以可以理解為生成一個(gè)實(shí)例。那么自然也可以去調(diào)用則是配合使用的。等于是等待一個(gè)返回值,等待的執(zhí)行結(jié)果。但是函數(shù)不會(huì)造成阻塞,所以配合使用,則沒(méi)有影響到外部。 在異步編程中,es6提供了promise對(duì)象的方式。簡(jiǎn)單的用法 var promise = new Promise((resolve,reject)=>{ if(){ ...
摘要:理解承諾有兩個(gè)部分。如果異步操作成功,則通過(guò)的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯(cuò)誤,則通過(guò)調(diào)用函數(shù)傳遞錯(cuò)誤具體信息。這將與理解對(duì)象密切相關(guān)。這個(gè)函數(shù)將創(chuàng)建一個(gè),該將在到秒之間的隨機(jī)數(shù)秒后執(zhí)行或。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:理解承諾有兩個(gè)部分。如果異步操作成功,則通過(guò)的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯(cuò)誤,則通過(guò)調(diào)用函數(shù)傳遞錯(cuò)誤具體信息。這將與理解對(duì)象密切相關(guān)。這個(gè)函數(shù)將創(chuàng)建一個(gè),該將在到秒之間的隨機(jī)數(shù)秒后執(zhí)行或。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:有一個(gè)和相關(guān)的更大的問(wèn)題。最后,請(qǐng)負(fù)有責(zé)任感并且使用安全的擴(kuò)展。深入理解五部曲異步問(wèn)題深入理解五部曲轉(zhuǎn)換問(wèn)題深入理解五部曲可靠性問(wèn)題深入理解五部曲擴(kuò)展性問(wèn)題深入理解五部曲樂(lè)高問(wèn)題最后,安利下我的個(gè)人博客,歡迎訪問(wèn) 原文地址:http://blog.getify.com/promis... 現(xiàn)在,我希望你已經(jīng)看過(guò)深入理解Promise的前三篇文章了。并且假設(shè)你已經(jīng)完全理解Promises...
閱讀 3415·2021-10-11 11:06
閱讀 2195·2019-08-29 11:10
閱讀 1957·2019-08-26 18:18
閱讀 3264·2019-08-26 13:34
閱讀 1572·2019-08-23 16:45
閱讀 1047·2019-08-23 16:29
閱讀 2810·2019-08-23 13:11
閱讀 3244·2019-08-23 12:58