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