Promise 對象使用 ★ Promise 基本認識 Promise 是一個對象,用於表示非同步操作的最終完成(或失敗)及其結果值。它允許你關聯處理程式,這些處理程式將在非同步操作成功完成時或者失敗時調用,從而避免了更複雜的嵌套回調(即回調地獄)。Promise 對象通常用於執行非同步操作,如網路請求、 ...
Promise
對象使用
★ Promise
基本認識
Promise 是一個對象,用於表示非同步操作的最終完成(或失敗)及其結果值。它允許你關聯處理程式,這些處理程式將在非同步操作成功完成時或者失敗時調用,從而避免了更複雜的嵌套回調(即回調地獄)。Promise 對象通常用於執行非同步操作,如網路請求、文件操作等。它提供了 .then() 和 .catch() 方法來處理 Fulfilled 和 Rejected 狀態的結果。
★ Promise 使用語法
proObj = new Promise((resolved, rejected) => {
resolved("成功的返回值");
rejected("失敗的返回值");
});
proObj
.then("處理成功情況的回調函數", "處理失敗情況的回調函數")
.catch("處理 Promise 失敗的情況")
★ Promise
主要特點
-
非同步操作的代理:
一個 Promise 對象代表一個可能還未完成,也可能已經完成的非同步操作。
-
狀態:
Promise
對象有三種狀態Pending
(進行中):初始狀態,既不是成功,也不是失敗狀態。Fulfilled
(已成功):意味著操作成功完成。Rejected
(已失敗):意味著操作失敗。
-
不可變性:
Promise的狀態一旦確定,就不會再改變。這意味著一個Promise對象要麼處於pending狀態,要麼處於fulfilled狀態,要麼處於rejected狀態,而且它不會同時處於兩種狀態中。這種不可變性是Promise機制的一個重要特性,它確保了非同步操作的結果一旦確定,就不會因為後續的代碼執行而發生變化.此外,Promise的狀態轉換隻能從pending到fulfilled或從pending到rejected,不能反向轉換。這種單向的狀態轉換機制有助於避免在非同步操作中產生混亂和不可預測的行為
★ Promise
的鏈式調用
-
說明
Promise 允許鏈式調用 .then() 方法,每個 .then() 可以返回一個新的 Promise,使得非同步操作可以順序執行。
-
示例
doSomething() .then(function(result) { return doSomethingElse(result); }) .then(function(newResult) { return doThirdThing(newResult); }) .then(function(finalResult) { console.log('Got the final result: ' + finalResult); }) .catch(failureCallback);
-
優點
- 提供了一種更加優雅的方式來處理非同步操作。
- 解決了回調地獄問題,使代碼更加清晰和易於維護。
-
缺點
- 不能取消
Promise
,一旦新建它就會立即執行,無法中途取消。 - 如果不設置回調函數,
Promise
內部拋出的錯誤不會反映到外部。 - 當處於 Pending 狀態時,無法得知當前進展到哪一個階段(剛開始還是即將完成)。
- 不能取消
★ Promise
應用場景
-
1-模擬請求數據
let pro = new Promise(function (resolved, rejected) { // 執行非同步操作 let res = { // code: 200, // data:{ // name:'FL' // }, code: 500, error: '伺服器錯誤' }; setTimeout(() => { if (res.code === 200) { resolved(res.data); } else { rejected(res.error); } }, 1000) }); pro.then((res) => { console.log(res); }, (error) => { console.log(error); }).catch(() => console.log('Promise 失敗'));
-
2-封裝超時時間
function timeOut(ms) { return new Promise((resolved, rejected) => { setTimeout(() => { resolved('hello promise success!!'); }, ms); }) } timeOut(2000).then((res) => { console.log(res); })
-
3-使用promise封裝ajax
// http://ajax-base-api-t.itheima.net/api/getbooks function getJSON(url){ return new Promise((resolve, reject)=>{ const xhr = new XMLHttpRequest(); xhr.open("GET", url); // 監控狀態 xhr.onreadystatechange = handler; // 聲明相應數據類型 xhr.responseType = "json"; xhr.setRequestHeader('Accept', 'application/json'); // 發送請求 xhr.send(); function handler(){ console.log(this); console.log(this.readyState); if(this.readyState === 4){ if(this.status === 200){ resolve(this.response); }else{ reject(new Error(this.statusText)); } } } }) } // then()返回一個新的promise實例,可以採用鏈式編程(將上一級的返回值作為下一級的實參) var a = getJSON('http://ajax-base-api-t.itheima.net/api/getbooks') .then((data)=>{ console.log(data); // 返回值作為下一級then的實參 return data.data; },(error)=>{ console.log(error); }) .then((twoStageData)=>{ console.log(twoStageData); }); console.log(a);
★ then
的第二參數與catch
區別
在JavaScript中使用
Promise
時,.then()
方法可以接受兩個參數:第一個是處理成功情況的回調函數,第二個是處理失敗情況的回調函數。而.catch()
方法則專門用於處理Promise
失敗的情況。雖然這兩種方式都可以用來處理錯誤,但它們之間存在一些重要的區別:
-
.then()
的第二個參數-
.then()
的作用.then() 方法的第二個參數是一個可選的錯誤處理函數,用於處理 Promise 被拒絕(Rejected)的情況。
-
使用
.then()
的第二個參數處理錯誤有以下特點:- 作用域限制:這個錯誤處理函數只捕獲到該
.then()
前面的錯誤,如果在.then()
的第一個回調函數(處理成功的回調)中發生錯誤,這個錯誤不會被第二個參數捕獲。 - 鏈式調用:如果
.then()
的第一個回調函數中發生了錯誤,而沒有提供第二個錯誤處理函數,這個錯誤會被傳遞到鏈中下一個.catch()
或.then()
的第二個參數中。
- 作用域限制:這個錯誤處理函數只捕獲到該
-
-
.catch()
-
.catch()
的作用.catch() 方法專門用來捕獲鏈中前面任何 Promise 的錯誤。 promise .then(function(value) { /* 處理成功 */ }) .catch(function(error) { /* 處理所有前面的錯誤 */ });
-
使用
.catch()
的優點包括:- 集中處理錯誤:
.catch()
可以捕獲鏈中前面任何Promise
的錯誤,包括前面.then()
中的成功回調里拋出的異常。 - 提高可讀性:使用
.catch()
可以使得錯誤處理更加集中和明確,代碼更易於理解和維護。
- 集中處理錯誤:
-
-
結論
雖然 .then() 的第二個參數和 .catch() 都可以用來處理錯誤,但推薦使用 .catch(),因為它可以捕獲整個鏈中的錯誤,使得錯誤處理更加集中和清晰。此外,使用 .catch() 也可以避免某些由於遺漏錯誤處理函數而導致的難以追蹤的錯誤。
★ Promise
對象的其他方法
-
resolve()
將現有的任何對象轉換成Promise
對象let p = Promise.resolve('foo'); // 等價於 // let p = new Promise(resolve => resolve('foo')); console.log(p); p.then((data)=>{ console.log(data)});
-
all()
多個Promise
對象運行結果的合併處理-
應用說明
一些游戲類的素材比較多,等待圖片、flash、靜態資源文件都載入完成才進行頁面初始化
-
示例
let promise1 = new Promise((resolve, reject)=>{}); let promise2 = new Promise((resolve, reject)=>{}); let promise3 = new Promise((resolve, reject)=>{}); let p4 = Promise.all([promise1, promise2, promise3]); p4.then(()=>{ // 三個promise都成功, 才執行 }).catch((err)=>{ // 有一個promise失敗, 就執行 });
-
-
race()
-
應用說明
Promise.race() 是一個 JavaScript 方法,它接受一個 Promise 對象的數組作為輸入,並返回一個新的 Promise。這個新的 Promise 將會解決(fulfill)或拒絕(reject)為最先解決或拒絕的輸入 Promise 的結果;Promise.race() 是處理多個非同步操作中最快一個的結果的有效工具。它在需要快速響應的場景或需要處理多個可能的非同步結果時非常有用。
-
使用場景
- 超時處理:可以與超時邏輯配合使用,比如設置一個時間限制,如果某個操作在指定時間內沒有完成,則自動拒絕。
- 競爭條件:當多個非同步操作競爭同一個資源時,只需要結果最快的一個。
- 錯誤恢復:可以啟動多個相同的非同步操作,如果其中一個失敗了,其他的仍然可以繼續,從而提高系統的健壯性。
-
示例
// 應用: 監控圖片載入過程, 超過設置的載入時間則停止載入並執行超時處理函數 function requestImg(imgSrc) { return new Promise((resolve, reject)=>{ // 創建圖片對象 const img = new Image(); img.onload = function(){ resolve(img); }; img.src = imgSrc }) } function timeOut(){ return new Promise((resolve, reject)=>{ setTimeout(()=>{ reject('圖片請求超時!') }, 1000); }) } Promise.race([requestImg('https://img0.baidu.com/it/u=2020518972,2077284106&fm=253&fmt=auto&app=120&f=JPEG?w=889&h=500'), timeOut()]) .then(res=>{ console.log('then'); console.log(res); document.body.appendChild(res); }).catch(err=>{ console.log('catch'); console.log(err); })
-
-
done()
finally()
不管請求失敗還是成功都會執行的方法