您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript中Promise的原理是什么及如何使用的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaScript中Promise的原理是什么及如何使用文章都會有所收獲,下面我們一起來看看吧。
按照我往常的理解,Promise是一個構造函數,有all、resolve、reject、then、catch等幾個方法,一般情況下,在涉及到異步操作時才會用到Promise。
所以我接下來先new一個Promise對象,并在其中進行一些異步操作:
// 使用Promise的時候一般會把它包裹在一個函數中,并在函數的最后返回這個Promise對象 function runPro()( var a = new Promise((resolve, reject) => { setTimeout(() => { console.log('work done!'); resolve('success'); }, 1000); }); return a; ) runPro()
在上面的代碼中,Promise的構造函數接收一個箭頭函數作為參數,這個箭頭函數又有兩個參數,分別是resolve和reject,我在這個箭頭函數中使用setTimeout進行了一些異步操作,異步操作中執行了resolve方法,并給resolve方法傳了一個字符串‘success’作為參數。
執行這段代碼會發現,等待了1秒鐘后(因為我在setTimeout中設置的等待時間是1000毫秒),輸出了‘work done!’。
這時候并沒有發現Promise有什么特別的作用,而且resolve和reject這兩個的作用也并沒有體現出來。
之前我們說過Promise這個構造函數上有then、catch方法,在上面的代碼片段中,runPro函數最后return了一個Promise對象,所以我們可以在runPro函數執行完成之后使用then對Promise對象進行進一步的操作:
runPro().then((res) => { console.log('then:', res); //TODO something });
輸出結果:
在runPro返回的Promise對象上直接調用then方法,then方法接收一個函數作為參數A,并且這個箭頭函數也會接收一個參數B,這個參數B的值就是前面代碼中resolve方法所傳遞的字符串‘success’。
執行代碼,會在1秒后首先輸出‘work done!’,緊接著輸出‘then: success’。
這個時候,就可以簡單的體現出來Promise的作用了,在前面的代碼中,then方法就像是Promise的回調函數,當Promise中的異步操作執行完之后,通過鏈式調用的方式執行回調函數。
這里的關鍵點就在于鏈式調用上,當實際使用中遇見多層回調的情況時,Promise的強大之處才能夠體現出來:
function runPro2(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro2'); }, 1000); }); return a; }; function runPro3(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro3'); }, 1000); }); return a; }; runPro().then(() => { return runPro2(); }).then(() => { return runPro3(); }).then(() => { console.log('all done') })
到這里為止,大概已經明白了,Promise是一個在異步操作過程中,等待其中異步操作完成之后執行其回調函數的一種結構體。但是其中的原理還是模糊不清,其中resolve和reject這兩個參數還沒有搞清楚,只知道在前面的幾個代碼片段中都調用了resolve函數,resolve是做什么的并沒有體現出來。
關于resolve和reject,我以前的理解是Promise中的異步操作執行成功后調用resolve函數,異步操作執行失敗后調用reject函數,后來發現這種理解其實是不準確的。
在理解這兩個函數的正確作用之前,我們首先要知道Promise一個重要的特性:狀態
Promise的狀態:
一個Promise對象的當前狀態必須為以下三種狀態中的一種:等待(Pending)、完成(Fulfilled)、拒絕(Rejected)。
Pending:
異步操作完成之前,Promise處于等待狀態,這時候的Promise可以遷移至Fulfilled或者Rejected。
Fulfilled:
異步操作完成之后,Promise可能從Pending狀態遷移至Fulfilled狀態,Fulfilled狀態的Promise必須擁有一個不可變的終值,并且Fulfilled狀態的Promise不能遷移為其他狀態。
Rejected:
異步操作完成之后,Promise可能從Pending狀態遷移至Rejected狀態,Rejected狀態的Promise必須擁有一個不可變的拒絕原因,并且Rejected狀態的Promise不能遷移為其他狀態。
了解了Promise的三種狀態之后,我們再來說說resolve和reject這兩個函數的作用:
resolve函數將Promise設置為Fulfilled狀態,reject函數將Promise設置為Rejected狀態。
設置為Fulfilled或者rejected狀態后,即表示Promise中的異步操作執行完成,這時程序就會執行then回調函數。
resolve和reject函數傳遞的參數,將由then函數中的箭頭函數接收。
實際上,理解Promise的關鍵點就在于這個狀態,通過維護狀態、傳遞狀態的方法來進行及時的回調。
所以,如下面代碼所示,當使用Promise進行異步操作的時候,其中有幾個關鍵點需要特別注意:
在一個函數中new了一個Promise對象之后,函數的最后必須把這個Promise對象return出來,否則這個函數就無法使用then函數進行回調;
異步操作中必須執行resolve或者reject函數,否則這個Promise一直處于Pending狀態,代碼就不會執行它的回調函數。
function runPro(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('resolve'); console.log('this is runPro'); }, 1000); }); return a; } runPro().then((res) => { console.log(res); })
同樣的道理,當異步操作執行失敗時,代碼通過執行reject函數的方式,將Promise的狀態設置為Rejected,并返回一個拒絕原因:
function runPro(item){ var a = new Promise((resolve, reject) => { setTimeout(() => { if(item >= 18) { console.log('item 大于 18'); resolve('一切正常!'); }else { console.log('item 小于 18'); reject('18+電影不允許放映!'); } }, 1000); }); return a; } runPro(13) .then((res) => { console.log('resolve:',res); },(rej) => { console.log('reject:', rej); })
我們給runPro函數傳遞不同的參數,runPro接受參數后進行一個異步的判斷,如果這個參數的值小于18,執行reject函數,反之則執行resolve函數,異步操作完成之后,執行then回調函數,這里的回調函數可以接收兩個箭頭函數作為參數,分別對應了resolve函數的回調和reject函數的回調,這兩個箭頭函數可以分別拿到resolve和reject傳遞的參數。
如下面截圖所示,分別給runPro傳遞兩個不同值后,得到了兩種不同的結果:
catch函數的用法
在Promise中,catch函數可以替代reject函數使用,用來指定接收reject的回調:
function runPro(item){ var a = new Promise((resolve, reject) => { setTimeout(() => { if(item >= 18) { console.log('item 大于 18'); resolve('一切正常!'); }else { console.log('item 小于 18'); reject('18+電影不允許放映!'); } }, 1000); }); return a; } runPro(13) .then((res) => { console.log('resolve:',res); }) .catch((rej) => { console.log('catch:', rej); })
如上面代碼所示,對調函數then只有一個箭頭函數作為參數,這種情況下,這個箭頭函數就被指定用來接收resolve函數的回調,而reject函數的回調則被catch函數來接收:
這個地方使用catch函數來接收reject的回調有一個優點,當前面的then回調函數中出現位置錯誤時,catch函數可以對錯誤信息進行處理,而不會導致代碼報錯。這個原理和常用的try/catch語句相同。
function runPro(item){ var a = new Promise((resolve, reject) => { setTimeout(() => { if(item >= 18) { console.log('item 大于 18'); resolve('一切正常!'); }else { console.log('item 小于 18'); reject('18+電影不允許放映!'); } }, 1000); }); return a; } runPro(19) .then((res) => { console.log(adc); // 這里的adc是一個未定義的變量,當代碼執行到這里時,會拋出Error信息導致代碼卡死 console.log('resolve:',res); }, (rej) => { console.log('reject:',rej); }); runPro(19) .then((res) => { console.log(abc); // 這里的abc是一個未定義的變量,但是由于后邊使用.catch函數進行了異常捕獲,所以程序不會報錯。而且錯誤原因也會作為參數傳遞到后面.catch函數的參數中 console.log('resolve:',res); }) .catch((rej) => { console.log('catch:', rej); })
all函數 / race函數并行異步操作
Promise的all函數和race函數都提供了并行異步操作的能力,二者的區別在于,當這些并行的異步操作耗時不同時,all函數是在所有的異步操作都執行完之后才會執行,而race函數則會在第一個異步操作完成之后立即執行。
function runPro1(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro1'); }, 1000); }); return a; } function runPro2(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro2'); }, 2000); }); return a; }; function runPro3(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro3'); }, 3000); }); return a; }; Promise.all([runPro1(), runPro2(), runPro3()]) .then((res) => { console.log('all:', res); })
function runPro1(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro1'); }, 1000); }); return a; } function runPro2(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro2'); }, 2000); }); return a; }; function runPro3(){ var a = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); console.log('this is runPro3'); }, 3000); }); return a; }; Promise.races([runPro1(), runPro2(), runPro3()]) .then((res) => { console.log('all:', res); })
如上兩個代碼片段所示,all函數和race都接收一個數組作為參數,這個數組中的值就是我們要進行并行執行的異步操作。這里我們同樣使用then函數作為異步操作完成的回調函數。同時我們通過console輸出發現,在race函數的回調函數開始執行的時候,另外兩個沒有執行完成的異步操作并沒有停止,依舊在執行。
關于“JavaScript中Promise的原理是什么及如何使用”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaScript中Promise的原理是什么及如何使用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。