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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...