溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ES6的Promise怎么用

發(fā)布時(shí)間:2021-12-15 13:31:15 來源:億速云 閱讀:214 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“ES6的Promise怎么用”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“ES6的Promise怎么用”這篇文章吧。

什么是Promise

Promise 是異步編程的一種解決方案,其實(shí)是一個(gè)構(gòu)造函數(shù),自己身上有all、reject、resolve這幾個(gè)方法,原型上有then、catch等方法。(ps:什么是原型:http://kemok4.com/article/231967.htm)

Promise對(duì)象有以下兩個(gè)特點(diǎn)。

  • (1)對(duì)象的狀態(tài)不受外界影響。Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。V挥挟惒讲僮鞯慕Y(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài)。這也是Promise這個(gè)名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。

  • (2)一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果,這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對(duì)Promise對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。這與事件(Event)完全不同,事件的特點(diǎn)是,如果你錯(cuò)過了它,再去監(jiān)聽,是得不到結(jié)果的。

下面先 new一個(gè)Promise

let p = new Promise(function(resolve, reject){
		//做一些異步操作
		setTimeout(function(){
			console.log('執(zhí)行完成Promise');
			resolve('要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回?cái)?shù)據(jù)');
		}, 2000);
	});

刷新頁面會(huì)發(fā)現(xiàn)控制臺(tái)直接打出

ES6的Promise怎么用

其執(zhí)行過程是:執(zhí)行了一個(gè)異步操作,也就是setTimeout,2秒后,輸出“執(zhí)行完成”,并且調(diào)用resolve方法。

注意!我只是new了一個(gè)對(duì)象,并沒有調(diào)用它,我們傳進(jìn)去的函數(shù)就已經(jīng)執(zhí)行了,這是需要注意的一個(gè)細(xì)節(jié)。所以我們用Promise的時(shí)候一般是包在一個(gè)函數(shù)中,在需要的時(shí)候去運(yùn)行這個(gè)函數(shù),如:

<div onClick={promiseClick}>開始異步請(qǐng)求</div>
 
const promiseClick =()=>{
	 console.log('點(diǎn)擊方法被調(diào)用')
	 let p = new Promise(function(resolve, reject){
		//做一些異步操作
		setTimeout(function(){
				console.log('執(zhí)行完成Promise');
				resolve('要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回?cái)?shù)據(jù)');
			}, 2000);
		});
        return p
	}

刷新頁面的時(shí)候是沒有任何反映的,但是點(diǎn)擊后控制臺(tái)打出

ES6的Promise怎么用

當(dāng)放在函數(shù)里面的時(shí)候只有調(diào)用的時(shí)候才會(huì)被執(zhí)行

那么,接下里解決兩個(gè)問題:

  • 1、為什么要放在函數(shù)里面

  • 2、resolve是個(gè)什么鬼

我們包裝好的函數(shù)最后,會(huì)return出Promise對(duì)象,也就是說,執(zhí)行這個(gè)函數(shù)我們得到了一個(gè)Promise對(duì)象。接下來就可以用Promise對(duì)象上有then、catch方法了,這就是Promise的強(qiáng)大之處了,看下面的代碼:

promiseClick().then(function(data){
    console.log(data);
    //后面可以用傳過來的數(shù)據(jù)做些其他操作
    //......
});

這樣控制臺(tái)輸出

ES6的Promise怎么用

先是方法被調(diào)用起床執(zhí)行了promise,最后執(zhí)行了promise的then方法,then方法是一個(gè)函數(shù)接受一個(gè)參數(shù)是接受resolve返回的數(shù)據(jù)這事就輸出了‘要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回?cái)?shù)據(jù)'

這時(shí)候你應(yīng)該有所領(lǐng)悟了,原來then里面的函數(shù)就跟我們平時(shí)的回調(diào)函數(shù)一個(gè)意思,能夠在promiseClick這個(gè)異步任務(wù)執(zhí)行完成之后被執(zhí)行。這就是Promise的作用了,簡(jiǎn)單來講,就是能把原來的回調(diào)寫法分離出來,在異步操作執(zhí)行完后,用鏈?zhǔn)秸{(diào)用的方式執(zhí)行回調(diào)函數(shù)。

你可能會(huì)覺得在這個(gè)和寫一個(gè)回調(diào)函數(shù)沒有什么區(qū)別;那么,如果有多層回調(diào)該怎么辦?如果callback也是一個(gè)異步操作,而且執(zhí)行完后也需要有相應(yīng)的回調(diào)函數(shù),該怎么辦呢?總不能再定義一個(gè)callback2,然后給callback傳進(jìn)去吧。而Promise的優(yōu)勢(shì)在于,可以在then方法中繼續(xù)寫Promise對(duì)象并返回,然后繼續(xù)調(diào)用then來進(jìn)行回調(diào)操作。

所以:精髓在于:Promise只是能夠簡(jiǎn)化層層回調(diào)的寫法,而實(shí)質(zhì)上,Promise的精髓是“狀態(tài)”,用維護(hù)狀態(tài)、傳遞狀態(tài)的方式來使得回調(diào)函數(shù)能夠及時(shí)調(diào)用,它比傳遞callback函數(shù)要簡(jiǎn)單、靈活的多。所以使用Promise的正確場(chǎng)景是這樣的:

promiseClick()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});

這樣能夠按順序,每隔兩秒輸出每個(gè)異步回調(diào)中的內(nèi)容,在runAsync2中傳給resolve的數(shù)據(jù),能在接下來的then方法中拿到。

ES6的Promise怎么用

(Ps:此處執(zhí)行多次是因?yàn)檠芯吭撚梅ǖ臅r(shí)候我在一個(gè)react的demo中進(jìn)行的,該頁面多個(gè)元素改變導(dǎo)致頁面多次渲染執(zhí)行所致,正常頁面只渲染一次的話就所有只會(huì)執(zhí)行一次)

reject的用法

以上是對(duì)promise的resolve用法進(jìn)行了解釋,相當(dāng)于resolve是對(duì)promise成功時(shí)候的回調(diào),它把promise的狀態(tài)修改為

fullfiled,那么,reject就是失敗的時(shí)候的回調(diào),他把promise的狀態(tài)修改為rejected,這樣我們?cè)趖hen中就能捕捉到,然后執(zhí)行“失敗”情況的回調(diào)。

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved成功回調(diào)');
			console.log('成功回調(diào)接受的值:',data);
		}, 
		function(reason){
			console.log('rejected失敗回調(diào)');
			console.log('失敗執(zhí)行回調(diào)拋出失敗原因:',reason);
		}
	);	

執(zhí)行結(jié)果:

ES6的Promise怎么用

(PS:此處也是執(zhí)行多次所以輸出多次,執(zhí)行多次的原因和上次原因一致)

以上代碼:調(diào)用promiseClick方法執(zhí)行,2秒后獲取到一個(gè)隨機(jī)數(shù),如果小于10,我們算成功,調(diào)用resolve修改Promise的狀態(tài)為fullfiled。否則我們認(rèn)為是“失敗”了,調(diào)用reject并傳遞一個(gè)參數(shù),作為失敗的原因。并將狀態(tài)改成rejected

運(yùn)行promiseClick并且在then中傳了兩個(gè)參數(shù),這兩個(gè)參數(shù)分別是兩個(gè)函數(shù),then方法可以接受兩個(gè)參數(shù),第一個(gè)對(duì)應(yīng)resolve的回調(diào),第二個(gè)對(duì)應(yīng)reject的回調(diào)。(也就是說then方法中接受兩個(gè)回調(diào),一個(gè)成功的回調(diào)函數(shù),一個(gè)失敗的回調(diào)函數(shù),并且能在回調(diào)函數(shù)中拿到成功的數(shù)據(jù)和失敗的原因),所以我們能夠分別拿到成功和失敗傳過來的數(shù)據(jù)就有以上的運(yùn)行結(jié)果

catch的用法

與Promise對(duì)象方法then方法并行的一個(gè)方法就是catch,與try  catch類似,catch就是用來捕獲異常的,也就是和then方法中接受的第二參數(shù)rejected的回調(diào)是一樣的,如下:

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved成功回調(diào)');
			console.log('成功回調(diào)接受的值:',data);
		}
	)
	.catch(function(reason, data){
		console.log('catch到rejected失敗回調(diào)');
		console.log('catch失敗執(zhí)行回調(diào)拋出失敗原因:',reason);
	});	

執(zhí)行結(jié)果:

ES6的Promise怎么用

效果和寫在then的第二個(gè)參數(shù)里面一樣。它將大于10的情況下的失敗回調(diào)的原因輸出,但是,它還有另外一個(gè)作用:在執(zhí)行resolve的回調(diào)(也就是上面then中的第一個(gè)參數(shù))時(shí),如果拋出異常了(代碼出錯(cuò)了),那么并不會(huì)報(bào)錯(cuò)卡死js,而是會(huì)進(jìn)到這個(gè)catch方法中。如下:

function promiseClick(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
 
	promiseClick().then(
		function(data){
			console.log('resolved成功回調(diào)');
			console.log('成功回調(diào)接受的值:',data);
			console.log(noData);
		}
	)
	.catch(function(reason, data){
		console.log('catch到rejected失敗回調(diào)');
		console.log('catch失敗執(zhí)行回調(diào)拋出失敗原因:',reason);
	});	

執(zhí)行結(jié)果:

ES6的Promise怎么用

在resolve的回調(diào)中,我們console.log(noData);而noData這個(gè)變量是沒有被定義的。如果我們不用Promise,代碼運(yùn)行到這里就直接在控制臺(tái)報(bào)錯(cuò)了,不往下運(yùn)行了。但是在這里,會(huì)得到上圖的結(jié)果,也就是說進(jìn)到catch方法里面去了,而且把錯(cuò)誤原因傳到了reason參數(shù)中。即便是有錯(cuò)誤的代碼也不會(huì)報(bào)錯(cuò)了

all的用法

與then同級(jí)的另一個(gè)方法,all方法,該方法提供了并行執(zhí)行異步操作的能力,并且在所有異步操作執(zhí)行完后并且執(zhí)行結(jié)果都是成功的時(shí)候才執(zhí)行回調(diào)。

將上述方法復(fù)制兩份并重命名promiseClick3(), promiseClick2(), promiseClick1(),如下

function promiseClick1(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick2(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick3(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
 
	Promise
		.all([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(function(results){
			console.log(results);
		});

Promise.all來執(zhí)行,all接收一個(gè)數(shù)組參數(shù),這組參數(shù)為需要執(zhí)行異步操作的所有方法,里面的值最終都算返回Promise對(duì)象。這樣,三個(gè)異步操作的并行執(zhí)行的,等到它們都執(zhí)行完后才會(huì)進(jìn)到then里面。那么,三個(gè)異步操作返回的數(shù)據(jù)哪里去了呢?都在then里面,all會(huì)把所有異步操作的結(jié)果放進(jìn)一個(gè)數(shù)組中傳給then,然后再執(zhí)行then方法的成功回調(diào)將結(jié)果接收,結(jié)果如下:(分別執(zhí)行得到結(jié)果,all統(tǒng)一執(zhí)行完三個(gè)函數(shù)并將值存在一個(gè)數(shù)組里面返回給then進(jìn)行回調(diào)輸出):

ES6的Promise怎么用

這樣以后就可以用all并行執(zhí)行多個(gè)異步操作,并且在一個(gè)回調(diào)中處理所有的返回?cái)?shù)據(jù),比如你需要提前準(zhǔn)備好所有數(shù)據(jù)才渲染頁面的時(shí)候就可以使用all,執(zhí)行多個(gè)異步操作將所有的數(shù)據(jù)處理好,再去渲染

race的用法

all是等所有的異步操作都執(zhí)行完了再執(zhí)行then方法,那么race方法就是相反的,誰先執(zhí)行完成就先執(zhí)行回調(diào)。先執(zhí)行完的不管是進(jìn)行了race的成功回調(diào)還是失敗回調(diào),其余的將不會(huì)再進(jìn)入race的任何回調(diào)

我們將上面的方法延遲分別改成234秒

 function promiseClick1(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('2s隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('2s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 2000);
		   })
		   return p
	   }
	   function promiseClick2(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('3s隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('3s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 3000);
		   })
		   return p
	   }
	   function promiseClick3(){
		let p = new Promise(function(resolve, reject){
			setTimeout(function(){
				var num = Math.ceil(Math.random()*20); //生成1-10的隨機(jī)數(shù)
				console.log('4s隨機(jī)數(shù)生成的值:',num)
				if(num<=10){
					resolve(num);
				}
				else{
					reject('4s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');
				}
			}, 4000);
		   })
		   return p
	   }
 
	Promise
		.race([promiseClick3(), promiseClick2(), promiseClick1()])
		.then(function(results){
			console.log('成功',results);
		},function(reason){
			console.log('失敗',reason);
		});

當(dāng)2s后promiseClick1執(zhí)行完成后就已經(jīng)進(jìn)入到了then里面回調(diào),在then里面的回調(diào)開始執(zhí)行時(shí),promiseClick2()和promiseClick3()并沒有停止,仍舊再執(zhí)行。于是再過3秒后,輸出了他們各自的值,但是將不會(huì)再進(jìn)入race的任何回調(diào)。如圖2s生成10進(jìn)入race的成功回調(diào)后,其余函數(shù)繼續(xù)執(zhí)行,但是將不會(huì)再進(jìn)入race的任何回調(diào),2s生成16進(jìn)入了race的失敗回調(diào),其余的繼續(xù)執(zhí)行,但是將不會(huì)再進(jìn)入race的任何回調(diào)。

ES6的Promise怎么用

ES6的Promise怎么用

race的使用比如可以使用在一個(gè)請(qǐng)求在10s內(nèi)請(qǐng)求成功的話就走then方法,如果10s內(nèi)沒有請(qǐng)求成功的話進(jìn)入reject回調(diào)執(zhí)行另一個(gè)操作。

補(bǔ)充:(由于有人問我怎么實(shí)現(xiàn)race的使用比如可以使用在一個(gè)請(qǐng)求在10s內(nèi)請(qǐng)求成功的話就走then方法,如果10s內(nèi)沒有請(qǐng)求成功的話進(jìn)入reject回調(diào)執(zhí)行另一個(gè)操作。這個(gè)問題,想是我的表達(dá)有點(diǎn)問題,那我就舉個(gè)例子)

 //請(qǐng)求某個(gè)table數(shù)據(jù)
    function requestTableList(){
        var p = new Promise((resolve, reject) => {
               //去后臺(tái)請(qǐng)求數(shù)據(jù),這里可以是ajax,可以是axios,可以是fetch 
                resolve(res);
        });
        return p;
    }
  //延時(shí)函數(shù),用于給請(qǐng)求計(jì)時(shí) 10s
      function timeout(){
          var p = new Promise((resolve, reject) => {
              setTimeout(() => {
                  reject('請(qǐng)求超時(shí)');
              }, 10000);
          });
          return p;
      }
      Promise.race([requestTableList(), timeout()]).then((data) =>{
        //進(jìn)行成功回調(diào)處理
        console.log(data);
      }).catch((err) => {
        // 失敗回調(diào)處理
          console.log(err);
      });

請(qǐng)求一個(gè)接口數(shù)據(jù),10s內(nèi)請(qǐng)求完成就展示數(shù)據(jù),10s內(nèi)沒有請(qǐng)求完成就提示請(qǐng)求失敗

這里定義了兩個(gè)promise,一個(gè)去請(qǐng)求數(shù)據(jù),一個(gè)記時(shí)10s,把兩個(gè)promise丟進(jìn)race里面賽跑去,如果請(qǐng)求數(shù)據(jù)先跑完就直接進(jìn)入.then成功回調(diào),將請(qǐng)求回來的數(shù)據(jù)進(jìn)行展示;如果計(jì)時(shí)先跑完,也就是10s了數(shù)據(jù)請(qǐng)求還沒有成功,就先進(jìn)入race的失敗回調(diào),就提示用戶數(shù)據(jù)請(qǐng)求失敗進(jìn)入.catch回調(diào),(ps:或者進(jìn)入reject的失敗回調(diào),當(dāng).then里面沒有寫reject回調(diào)的時(shí)候失敗回調(diào)會(huì)直接進(jìn)入.catch)

以上是“ES6的Promise怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI