ES6入門之Promise對象

来源:https://www.cnblogs.com/lieone/archive/2019/10/09/11642066.html
-Advertisement-
Play Games

1. Promise 的含義 Promise 是非同步編程的一種解決方案,比傳統的解決方案 回調函數和事件更合理、更強大。 1.1 什麼是Promise 簡單來說就是一個容器,裡面保存著某個未來才會結束的事件(也就是非同步操作)的結果。從語法上來講,Promise是一個對象,從它可以獲取非同步操作的消息, ...


1. Promise 的含義

Promise 是非同步編程的一種解決方案,比傳統的解決方案--回調函數和事件更合理、更強大。

1.1 什麼是Promise

簡單來說就是一個容器,裡面保存著某個未來才會結束的事件(也就是非同步操作)的結果。從語法上來講,Promise是一個對象,從它可以獲取非同步操作的消息,它提供統一的API,各種非同步操作都可以用同樣的方法進行處理。

Promise有兩個特點:

1.1.1、對象的狀態不受外界影響。Promise對象代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態、任何其他操作都無法改版這個狀態。

1.1.2、一旦狀態改版,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只存在兩種可能:從 pending 變為 fulfilled 和 從 pending 變為 rejeced。只要這兩種情況發生,狀態就終止,不會再變了並一直保持這個結果。這時就稱為 resolved(已定型)。如果改版已經發生了,即使再對Promise對象添加回調函數,也會立即得到這個結果。如果你錯過了再想去監聽,是得不到結果的。

1.1.3、有了Promise對象,就可以將非同步操作以同步操作的流程顯示出來,這樣就避免了層層嵌套的回調函數。Promise對象提供統一的介面,使得控制非同步操作更加容易。

1.1.4、Promise也有一些缺點,就是無法取消 Promise,一旦建立就會立即執行,無法中途取消。如果不設置回調函數,Promise內部拋出的錯誤不會反應到外部。另外如果處於 pending 狀態時,是無法知道現在到了哪一個階段。

2. 基本用法

Promise對象是一個構造函數,用來生成Promise實例

const promise = new Promise((reolve, reject) => {
    if (// 非同步操作成功) {
        resolve(val)
    }else{
        reject(val)
    }
})

Promise 構造函數接受一個函數作為參數,該函數的兩個參數分別是 resolve 和 reject。

resolve:,將Promise對象的狀態從『未完成』變為『成功』(pending => resolved),在非同步操作成功時調用,並將非同步操作的結果作為參數傳遞出去。

reject:將Promise對象的狀態從『未完成』變為『失敗』(pending => rejected),在非同步操作失敗時調用,並將非同步操作的結果作為參數傳遞出去。

Promise 實例生成以後,可以用 then 方法分別指定 resolved 狀態和 rejected 狀態的回調函數。

promise.then((val) => {
    // success
},(err) => {
    // failure
})

then方法可以接受兩個回調函數作為參數。(第二個函數可選,這兩個函數都接受Promise對象傳出的值作為參數)

1、第一個回調函數在Promise對象的狀態變為『resolved』時調用。

2、第二個回調函數在Promise對象的狀態變為『rejected』時調用。

實例:

function timeout(ms) {
    retrun new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done')
    })
}

timeout(100)
.then((v) => {
    console.log(v)
})

上面代碼中,timeout方法返回一個Promise實例,表示一段時間以後才會發生的結果,過了 ms時間後,Promise狀態變為『resolved』然後就會觸發then方法綁定的回調函數。

Promise 建立後就會立即執行

let promise = new Promise((resolve, reject) => {
    console.log('Promise')
    resolve()
})

promise
.then(() => {
    console.log('resolved')
})

console.log('hh')

// Promise
// hh
// resolved

Promise建立後立即執行,首先輸出 「Promise」然後執行promise 的then函數,然後首先執行同步任務 輸出 hh 在執行 then方法的回調函數輸出resolved

如果調用 resolve 函數和 reject 函數時帶有參數,那麼它們的參數會被傳遞給回調函數。reject函數的參數通常是Error對象的實例,表示拋出的錯誤。resolve函數的參數除了正常的值以外,還有可能是一個Promise實例。resolve實在成功的時候調用,reject是在失敗的時候調用。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

上述代碼中:p1 和 p2都是Promise的實例,但是p2的 resolve方法將 p1作為參數,即一個非同步操作的結果返回是另一個非同步操作。

註意:p1的狀態就會傳遞給p2,p1的狀態決定了p2的狀態。如果p1的狀態是pending,那麼p2的回調函數就會等待p1的狀態改變;如果p1的狀態已經是 resolved 或者 rejected,那麼p2的回調函數會立即執行。

一般來說,調用resolve 或 reject以後,Promise的進程就就結束了,後續操作應該放到 then方法里,而不是直接寫在 resolve 或 reject 的後面。另外最後在它們之前加上 return語句。

3. Promise.prototype.then()

Promise實例具有 then 方法,then方法是定義在原型對象 Promise.prototype上的。它的作用是為 Promise 實例添加狀態改變時的回調函數。then 的第一個參數是 resolved狀態的回調函數,第二個參數是 rejected狀態的回調函數。

then方法返回的是一個新的 Promise 實例,不是原來那個,因此可以使用鏈式寫法。.then().then()

a().then((j) => {
    retrun j
}).then((i) => {
    console.log(i)
},(err)=>{
    console.log(err)
})

上面 第一個then方法指定的回調函數,返回的是另一個 Promise 對象。這時,第二個 then 方法指定的回調函數,就會等這個新的 Promise對象狀態發生變化,如果變為 resolved,就調用第一個回調函數,如果狀態變為 rejected,就調用第二個回調函數。

4. Promise.prototype.catch()

Promise.prototype.catch 方法是 .then(null, rejecton) 或 .then(undefined, rejection)的別名,用於指定發生錯誤時的回調函數。

a().then((p) => {
    // success
}).catch((err) => {
    console.log('err')
})

如果對象的狀態變為 resolved, 則會調用 then 方法指定的回調函數 success,如果非同步操作拋出錯誤,狀態就會變為 rejected,就會調用 catch 方法指定的回調函數處理這個錯誤。如果 then 方法指定的回調函數,在運行中拋出錯誤,也會被catch 方法捕獲。

另外reject方法的作用等同於拋出錯誤

如果 Promise狀態已經變成 resolved,再拋出錯誤是無效的。因為狀態一旦改版,就永遠保持,不會再變了。 而且Promise的錯誤有『冒泡』的性質,會一直向後傳遞,直到被捕獲位置,它的錯誤總會被下一個catch語句捕獲

建議:Promise 對象後面要跟catch方法,這樣可以處理 Promise 內部發生的錯誤。catch方法返回的還是一個 Promise 對象,因此後面還可以接著調用then方法。

註意: catch函數中的方法發生錯誤,如果後面沒有別的catch 方法,那麼錯誤將不會被捕獲,如果 catch 後面 還有catch ,第二個catch將會捕獲前一個catch方法拋出的錯誤。

5. Promise.prototype.finally()

finally 方法用於指定不管 Promise 對象最後狀態如何,都會執行的操作。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

以上,不管promise 最後的狀態,都會執行 finally 方法指定的函數。

finally 方法的回調函數不接受任何參數,所以就無法知道之前Promise狀態到底是 fulfilled 還是 rejected。所以在finally方法裡面的操作,是與之前狀態無關的而且不依賴於Promise的執行結果。

6. Promise.all()

Promise.all 方法用於將多個 Promise 實例,包裝成一個新的 Promise實例。

const p = Promise.all([p1, p2, p3])

Promise.all 方法接受一個數組作為參數,p1、p2、p3都是Promise實例,如果不是,就會先調用Promise.resolve方法,將參數轉為 Promise 實例再處理。(Promise.all 方法的參數可以不是數組,但必須具有 Iterator 介面,且返回的每個成員都是 Promise 實例。)

Promise.all 的狀態有兩種情況:

1、如果 p1 p2 p3的狀態都變成了 fulfilled,p的狀態才是fulfilled,這時候返回一個 p1 p2 p3返回值組成的數組,傳遞給 p 的回調函數。

2、如果 p1 p2 p3中任一一個被rejected,p 的狀態就變成了 rejected,這時候返回的是第一個被 rejected 實例的返回值,傳遞給 p 的回調函數。

註意,如果作為參數的 Promise 實例,自己定義了catch方法,那麼它一旦被rejected,並不會觸發Promise.all()的catch方法。而是觸發自己定義的catch方法。

7. Promise.race()

Promise.race方法同樣是將多個 Promise 實例,包裝成一個新的 Promise實例。

const p = Promise.race([p1, p2, p3]);

與 Promise.all 的區別就是 p1 p2 p3 中一個實例改變狀態,那麼 p 的狀態就跟著改變了,返回值為最先返回那個Promise實例的返回值。

8. Promise.resolve()

將現有對象轉為 Promise 對象。

1、如果參數是一個Promise 實例
那麼將不做任何修改。
2、參數是一個 thenable對象(具有then方法的對象)
將這個對象轉為Promise對象,然後立即執行 thenable對象的then方法
3、參數不是具有then方法的對象,或根本不是對象
返回一個新的Promise對象,狀態為 resolved
4、不帶任何參數
直接返回一個 resolved 狀態的Promise對象

9. Promise.reject()

Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態為rejected。回調函數立即執行。

關註公眾號 【小夭同學】

公眾號小夭同學


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 23、$refs是什麼東東? 通過在標簽上設置ref屬性,然後在Vue實例方法中可以通過$refs拿到這些標簽,如: 24、對於多級嵌套組件,後代組件如何拿到父級或祖父級,設置更高級別的組件的數據或方法? 使用依賴註入。 provide選項允許我們在當前組件指定我們想要提供給後代組件的數據/方法,比 ...
  • 故障藝術,英文名稱叫glitch,在很多賽博朋克作品中經常看到,其實就是故意表現一種顯示設備的小故障效果,抖音的圖標其實就是這種的效果,我們看下這個圖標 這個圖標中的紅色和藍色的偏移其實就是一種故障藝術,看到這個,我就能想到早年我家還沒有有線電視時,搖天線對電視信號的場景,信號一差就是對著電視一陣拳 ...
  • 作為前端,在工作中難免會遇到關於排版的問題,以下是我整理的一些關於CSS的技巧,希望對你能有幫助。 1、每個單詞的首字母大寫 一般我們會用JS實現,其實CSS就可以實現。 JS代碼: var str = 'hello world'; str.replace(/( |^)[a z]/g,(L)= L. ...
  • 1.引入外部樣式表的格式: <link rel=”stylesheet” type=”text/css” href=”../css/style1.css”> 2.樣式表第一行應註明編碼類型: @charset “utf-8”; 3.css語法: ①一個元素中多個屬性用分號隔開,多個元素之間用逗號隔開 ...
  • 在前端裡面,大家都知道,html中輸入空格或換行是識別不了是空格的,但是有時候需要實現,那麼該如何解決呢?主要有以下幾個方面: 1:常用的轉義:&nbsp; 2:使用全形拼音,然後輸入空格也可實現 3:用標簽 pre實現(一般很少用了) 4:用css text-indent實現(這個一般用於時間段首 ...
  • 1. _proto_和prototype prototype屬性是一個靜態屬性, _proto_屬性是一個實例屬性。 prototype表示類的原型對象,_proto_表示原型對象中定義的內部屬性[prototype]的值。 類的每一個實例都有一個_proto_屬性,用於引用創建它的構造方法的pro ...
  • 關於CSS的書寫規範和順序,是大部分前端er都必須要攻剋的一門關卡,如果沒有按照良好的CSS書寫規範來寫CSS代碼,會影響代碼的閱讀體驗。這裡總結了一個CSS書寫規範、CSS書寫順序供大家參考,這些是參考了國外一些文章以及我的個人經驗總結出來,我想對寫CSS的前端用戶來說是值得學習的。 CSS書寫順 ...
  • vue對比jquery vue:mvvm 數據驅動影響視圖 適用於複雜數據jquery:mvc 視圖塞入數據 適用於複雜視圖動效 (其實都是js 的封裝,以及對html 的擴展) 相關指令 v-text 等同大鬍子效果 但是會轉換為字元串 v-html 綁定html屬性 v-if三兄弟 只會渲染判斷 ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...