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