Javascript的異步函數(shù)和Promise對(duì)象你了解嗎
1、JS中的異步
1.1 同步
一般情況下,js的代碼都是自上而下順序
運(yùn)行的。例如:
let res = ''; res = '獲取到的結(jié)果!'; console.log(res);
結(jié)果:
很容易理解,我給res
賦了新值,然后輸出res
。這就是js的同步執(zhí)行
,這里的同步
,并不是一起執(zhí)行的意思,而是在一個(gè)線程
里順序執(zhí)行的意思。因?yàn)镴avaScript是單線程,所以所有程序都應(yīng)該在一個(gè)線程里運(yùn)行。
1.2 異步
但是有的時(shí)候,我們獲取
res
的值是需要一點(diǎn)時(shí)間的,例如使用ajax向服務(wù)器發(fā)起請(qǐng)求,服務(wù)器響應(yīng)以后返回結(jié)果,我們?cè)賹⒔Y(jié)果賦值給res。
這里使用setTimeout函數(shù)模擬數(shù)據(jù)請(qǐng)求,setTimeout
也是一個(gè)異步函數(shù)。
let res = ''; setTimeout(()=>{ res = '獲取到的結(jié)果!'; console.log('獲取到結(jié)果了!',res); },3000); console.log('res',res);
可以看到,沒有立刻獲取到結(jié)果,而是3s后才獲取到結(jié)果。
為什么會(huì)這樣呢?
由于獲取res它是一個(gè)異步操作,所以它會(huì)被分為兩部分來執(zhí)行,先調(diào)用setTimeout方法,然后把要執(zhí)行的函數(shù)放到一個(gè)隊(duì)列中。代碼繼續(xù)往下執(zhí)行,當(dāng)把所有的代碼都執(zhí)行完后,放到隊(duì)列中的函數(shù)才會(huì)被執(zhí)行。因?yàn)閖s的單線程機(jī)制,不允許它花費(fèi)時(shí)間去等待異步函數(shù)的結(jié)果。
1.3 回調(diào)函數(shù)解決異步問題
既然異步函數(shù)的結(jié)果會(huì)再最后獲取,那么我們就可以給異步函數(shù)中加一個(gè)回調(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é)果,那還好。但是如果我們?cè)讷@取結(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);
雖然上述代碼會(huì)按照我們預(yù)期的方向運(yùn)行,但是多層的嵌套讓代碼閱讀和維護(hù)起來十分的困難。
2、Promise對(duì)象
2.1 Promise的基本使用
為了解決異步中的回調(diào)地獄問題,ES6引入了Promise對(duì)象
,使得我們可以十分優(yōu)雅地進(jìn)行異步操作。
從語法上來說,Promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息。
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也很容易理解,就是上一個(gè)異步函數(shù)執(zhí)行完成后,接著要進(jìn)行的操作。
同時(shí)Promise對(duì)象也可以通過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()對(duì)應(yīng)then的結(jié)果,而reject()對(duì)應(yīng)catch的結(jié)果。這在axios的請(qǐng)求操作中是十分常見的。
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個(gè)或者多個(gè)await表達(dá)式。await表達(dá)式會(huì)暫停整個(gè)async函數(shù)的執(zhí)行進(jìn)程并出讓其控制權(quán),只有當(dāng)其等待的基于promise的異步操作被兌現(xiàn)或被拒絕之后才會(huì)恢復(fù)進(jìn)程。promise的解決值會(huì)被當(dāng)作該await表達(dá)式的返回值。使用async / await關(guān)鍵字就可以在異步代碼中使用普通的try / catch代碼塊。
function getProcessedData(url) { return downloadData(url) // 返回一個(gè) promise 對(duì)象 .catch(e => { return downloadFallbackData(url) // 返回一個(gè) promise 對(duì)象 }) .then(v => { return processDataInWorker(v); // 返回一個(gè) promise 對(duì)象 }); }
使用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)文章
JavaScript資源預(yù)加載組件和滑屏組件的使用推薦
這篇文章主要介紹了JavaScript資源預(yù)加載組件和滑屏組件的使用推薦,分別為preload和slide的用法講解,使用起來非常簡單,需要的朋友可以參考下2016-03-03JavaScript+CSS實(shí)現(xiàn)的可折疊二級(jí)菜單實(shí)例
這篇文章主要介紹了JavaScript+CSS實(shí)現(xiàn)的可折疊二級(jí)菜單,以完整實(shí)例形式分析了JavaScript基于頁面元素節(jié)點(diǎn)及樣式的動(dòng)態(tài)操作實(shí)現(xiàn)折疊菜單的相關(guān)技巧,需要的朋友可以參考下2016-02-02JavaScript中的對(duì)象的extensible屬性介紹
這篇文章主要介紹了JavaScript中的對(duì)象的extensible屬性介紹,JavaScript中,對(duì)象的extensible屬性用于表示是否允許在對(duì)象中動(dòng)態(tài)添加新的property,需要的朋友可以參考下2014-12-12使用Web?Component實(shí)現(xiàn)防篡改水印
Web?Component內(nèi)部有鉤子天然支持被篡改時(shí)被觸發(fā),用來防篡改非常方便,所以本文就將使用Web?Component實(shí)現(xiàn)防篡改水印,感興趣的小伙伴可以了解下2023-12-12老生常談jacascript DOM節(jié)點(diǎn)獲取
下面小編就為大家?guī)硪黄仙U刯acascript DOM節(jié)點(diǎn)獲取。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04