Javascript的異步函數(shù)和Promise對象你了解嗎
1、JS中的異步
1.1 同步
一般情況下,js的代碼都是自上而下順序運(yùn)行的。例如:
let res = ''; res = '獲取到的結(jié)果!'; console.log(res);
結(jié)果:

很容易理解,我給res賦了新值,然后輸出res。這就是js的同步執(zhí)行,這里的同步,并不是一起執(zhí)行的意思,而是在一個線程里順序執(zhí)行的意思。因?yàn)镴avaScript是單線程,所以所有程序都應(yīng)該在一個線程里運(yùn)行。
1.2 異步
但是有的時候,我們獲取
res的值是需要一點(diǎn)時間的,例如使用ajax向服務(wù)器發(fā)起請求,服務(wù)器響應(yīng)以后返回結(jié)果,我們再將結(jié)果賦值給res。
這里使用setTimeout函數(shù)模擬數(shù)據(jù)請求,setTimeout也是一個異步函數(shù)。
let res = '';
setTimeout(()=>{
res = '獲取到的結(jié)果!';
console.log('獲取到結(jié)果了!',res);
},3000);
console.log('res',res);

可以看到,沒有立刻獲取到結(jié)果,而是3s后才獲取到結(jié)果。
為什么會這樣呢?
由于獲取res它是一個異步操作,所以它會被分為兩部分來執(zhí)行,先調(diào)用setTimeout方法,然后把要執(zhí)行的函數(shù)放到一個隊列中。代碼繼續(xù)往下執(zhí)行,當(dāng)把所有的代碼都執(zhí)行完后,放到隊列中的函數(shù)才會被執(zhí)行。因?yàn)閖s的單線程機(jī)制,不允許它花費(fèi)時間去等待異步函數(shù)的結(jié)果。
1.3 回調(diào)函數(shù)解決異步問題
既然異步函數(shù)的結(jié)果會再最后獲取,那么我們就可以給異步函數(shù)中加一個回調(diào)函數(shù),來處理獲取到的數(shù)據(jù)。
let res = '';
setTimeout(()=>{
res = '獲取到的結(jié)果!';
callback();
},3000);
function callback(){
console.log('獲取到結(jié)果了!',res);
console.log('處理結(jié)果!');
}
console.log('res', res);

現(xiàn)在console.log('res', res);仍然沒有獲取到res,但是我們已經(jīng)不需要它了,我們獲取res的就是為了處理它,而使用callback函數(shù)就可以達(dá)到目的了!
1.4 回調(diào)地獄
1.3了解了可以通過調(diào)用函數(shù)解決無法獲取結(jié)果的問題,但是它仍然是存在缺點(diǎn)的,如果只獲取一次結(jié)果,那還好。但是如果我們在獲取結(jié)果之后,還需要利用獲取的結(jié)果再進(jìn)行異步操作,那么又需要嵌套一層,又需要一次異步操作,再嵌套一層……
setTimeout(function(){
console.log("first");
setTimeout(function(){
console.log("second");
setTimeout(function(){
console.log("third");
setTimeout(function(){
console.log("fourth");
},2000);
},2000);
},2000);
},2000);
雖然上述代碼會按照我們預(yù)期的方向運(yùn)行,但是多層的嵌套讓代碼閱讀和維護(hù)起來十分的困難。
2、Promise對象
2.1 Promise的基本使用
為了解決異步中的回調(diào)地獄問題,ES6引入了Promise對象,使得我們可以十分優(yōu)雅地進(jìn)行異步操作。
從語法上來說,Promise是一個對象,從它可以獲取異步操作的消息。
let timeout = function(time){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},time);
});
}
console.log("開始運(yùn)行!");
timeout(2000).then(function(){
console.log("first");
return timeout(2000);
}).then(function(){
console.log("second");
return timeout(2000);
}).then(function(){
console.log("third");
return timeout(2000);
}).then(function(){
console.log("fourth");
return timeout(2000);
});

這樣就解決了上述的回調(diào)地獄的問題。并且then也很容易理解,就是上一個異步函數(shù)執(zhí)行完成后,接著要進(jìn)行的操作。
同時Promise對象也可以通過resolve和reject傳遞參數(shù):
let res = null;
let timeout = function(time){
return new Promise(function(resolve,reject){
setTimeout(function(){
res = false;
if(res){
resolve('res為true');
}else{
reject('res為false');
}
},time);
});
}
timeout().then((res)=>{
console.log(res);
}).catch((error)=>{
console.log(error);
})
這樣就可以根據(jù)res的值來確定結(jié)果了。resolve()對應(yīng)then的結(jié)果,而reject()對應(yīng)catch的結(jié)果。這在axios的請求操作中是十分常見的。
2.2 async 和 await
mdn描述如下:
async函數(shù)是使用async關(guān)鍵字聲明的函數(shù)。 async函數(shù)是AsyncFunction構(gòu)造函數(shù)的實(shí)例, 并且其中允許使用await關(guān)鍵字。async和await關(guān)鍵字讓我們可以用一種更簡潔的方式寫出基于Promise的異步行為,而無需刻意地鏈?zhǔn)秸{(diào)用promise。
async和await的關(guān)系:
async函數(shù)可能包含0個或者多個await表達(dá)式。await表達(dá)式會暫停整個async函數(shù)的執(zhí)行進(jìn)程并出讓其控制權(quán),只有當(dāng)其等待的基于promise的異步操作被兌現(xiàn)或被拒絕之后才會恢復(fù)進(jìn)程。promise的解決值會被當(dāng)作該await表達(dá)式的返回值。使用async / await關(guān)鍵字就可以在異步代碼中使用普通的try / catch代碼塊。
function getProcessedData(url) {
return downloadData(url) // 返回一個 promise 對象
.catch(e => {
return downloadFallbackData(url) // 返回一個 promise 對象
})
.then(v => {
return processDataInWorker(v); // 返回一個 promise 對象
});
}
使用async和await重寫上述函數(shù)。
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch (e) {
v = await downloadFallbackData(url);
}
return processDataInWorker(v);
}
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
基于jsbarcode 生成條形碼并將生成的條碼保存至本地+源碼
這篇文章主要介紹了基于jsbarcode 生成條形碼并將生成的條碼保存至本地,本文給大家提供最新源代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2020-04-04
用VsCode編輯TypeScript的實(shí)現(xiàn)方法
這篇文章主要介紹了用VsCode編輯TypeScript的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
JavaScript實(shí)現(xiàn)將數(shù)組數(shù)據(jù)添加到Select下拉框的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)將數(shù)組數(shù)據(jù)添加到Select下拉框的方法,涉及javascript數(shù)組操作及頁面元素動態(tài)賦值的相關(guān)技巧,需要的朋友可以參考下2015-08-08
JS小數(shù)轉(zhuǎn)換為整數(shù)的方法分析
這篇文章主要介紹了JS小數(shù)轉(zhuǎn)換為整數(shù)的方法,結(jié)合實(shí)例形式分析了數(shù)值轉(zhuǎn)換的常用方法與使用技巧,需要的朋友可以參考下2017-01-01

