其實(shí)關(guān)于異步的處理,我個(gè)人是大體已經(jīng)明白了其語法及實(shí)現(xiàn)方式了陪踩,但我就卡在了一個(gè)問題上,異步存在的意義是什么悉抵?關(guān)于這一點(diǎn)肩狂。。我想了大概兩天(屬于是豬腦過載了)姥饰,然后在晚上打游戲的時(shí)候傻谁,看著兵線過塔,突然明白了異步是干什么的列粪,于是果斷投降审磁,開始了這篇文章。
異步的意義
那么首先追問意義前岂座,先要知道異步是啥态蒂。我先寫一段同步代碼:
console.log(1);console.log(2);console.log(3);
那么在控制臺(tái)中,輸出的就是 1 2 3
接下來看下面這段異步代碼:
console.log(1);let time = setTimeout(() => {console.log(2)},0);console.log(3)
ok费什,那么這段代碼的輸出是什么呢钾恢?答案是 1? 3? 2
由此可以看出,所謂同步就是按照順序鸳址,從上而下瘩蚪,一種存在阻塞的編碼。而異步打破了這種規(guī)律稿黍,是一種非阻塞的編程疹瘦。
雖然我寫的這個(gè)代碼很簡單,但我覺得已經(jīng)充分說明了問題巡球。因?yàn)镴avaScript是一種自上而下編譯的代碼言沐,所以就有一個(gè)先來后到的規(guī)則邓嘹,就假如馬路上都是小轎車,這時(shí)候突然開進(jìn)來一臺(tái)重型卡車险胰,那么是不是會(huì)造成堵塞吴超?如果這輛卡車不開過去,那后面的小轎車是否就無法正常運(yùn)行鸯乃?這里的意義也是一樣鲸阻,在JavaScript中,也有函數(shù)會(huì)長期占用車道缨睡,比如延時(shí)器函數(shù)等鸟悴,那么這里就需要異步的存在,來將那些特殊的函數(shù)掛起奖年,在需要運(yùn)行或同步完成后再進(jìn)行细诸。
Promise對象
在上述代碼中,我使用了延時(shí)器函數(shù)來完成異步的操作陋守,但這是特例震贵,并不是說所有函數(shù)都能自主的完成異步操作。而在實(shí)際編程中水评,我們也并不總是要代碼自上而下執(zhí)行猩系,總有幾個(gè)特殊任務(wù)是需要掛起的,這時(shí)候中燥,就需要用的ES6提供的一個(gè)對象Promise對象寇甸。
promise是一個(gè)對象,同時(shí)也是一個(gè)構(gòu)造函數(shù)疗涉,通過promise可以new一個(gè)實(shí)例來幫助完成異步的處理拿霉,基本語法是:
let demo = new Promise((resolve,reject) => {})
這里不熟悉回調(diào)函數(shù)的可能會(huì)有點(diǎn)懵逼,如果懵逼的話我的建議是先不學(xué)習(xí)ES6咱扣。绽淘。因?yàn)檎娴臅?huì)暈掉的,看不懂又硬看闹伪,進(jìn)度真的很慢沪铭。
promise中以回調(diào)函數(shù)作為參數(shù),而回調(diào)函數(shù)中傳入兩個(gè)函數(shù)作為第二和第二參數(shù)祭往,這兩個(gè)中伦意,第一個(gè)參數(shù)resolve代表符合條件時(shí)觸發(fā)的邏輯火窒,reject作為不符合條件時(shí)觸發(fā)的參數(shù)硼补。那么下面我簡單的定義一個(gè)布爾值來補(bǔ)全這段代碼:
let isRun = true;
? ? ? ? let demo = new Promise((resolve,reject)=> {
? ? ? ? ? ? if (isRun) {
? ? ? ? ? ? ? ? resolve();
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? reject();
? ? ? ? ? ? }
? ? ? ? })
// 好了,到這里如果能看懂熏矿,那么可以繼續(xù)看已骇,看不懂的我就建議你反復(fù)閱讀上面內(nèi)容或者remake离钝。。
在上面代碼中褪储,我們就基本完整創(chuàng)建了一個(gè)異步實(shí)例卵渴,我們接下來就可以調(diào)用這個(gè)實(shí)例來處理我們需要異步的函數(shù)。
then()方法
該方法是由promise對象提供的方法鲤竹,我先抄一段大佬的解釋:then可以接收構(gòu)造函數(shù)中處理的狀態(tài)變化浪读,并分別對應(yīng)執(zhí)行。then方法有2個(gè)函數(shù)參數(shù)辛藻,第一個(gè)函數(shù)接收resolved(promise狀態(tài)為成功)的執(zhí)行碘橘,第二個(gè)函數(shù)接收reject(promise狀態(tài)為失敗)的執(zhí)行。
這里對于基礎(chǔ)不太好的人吱肌,可能又要暈了痘拆,所以其實(shí)可以不用糾結(jié)這段話中的狀態(tài)什么的,我們只要明白氮墨,接下來我們必須使用then()才能完成異步的操作纺蛆。上代碼:
let isRun = true;
? ? ? ? let demo = new Promise((resolve,reject)=> {
? ? ? ? ? ? if (isRun) {
? ? ? ? ? ? ? ? resolve('成功!');
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? reject();
? ? ? ? ? ? }
? ? ? ? })
? ? ? ? demo.then(
? ? ? ? ? ? (res) => {
? ? ? ? ? ? ? ? console.log(res);
? ? ? ? ? ? },
? ? ? ? ? ? (err) => {
? ? ? ? ? ? ? ? console.log('失敗了');
? ? ? ? ? ? }
? ? ? ? )
這里應(yīng)該能看到then的使用過程了规揪,在then中應(yīng)用了兩個(gè)回調(diào)函數(shù)作為參數(shù)桥氏,其中第一個(gè)參數(shù)接收執(zhí)行成功后返回的resolve,其實(shí)也就是resolve猛铅。
這里有關(guān)于resolve的形參傳遞的一個(gè)問題识颊,我這里直接標(biāo)注出來便于理解:
應(yīng)該很清晰了,前面實(shí)例的resolve的參數(shù)傳入了then中奕坟。這里要明白我的res到底是哪里來的祥款。
catch()方法
catch()方法是用來捕捉promise狀態(tài)為失敗的函數(shù),該函數(shù)只有一個(gè)回調(diào)函數(shù)作為參數(shù)月杉,也就是返回錯(cuò)誤信息刃跛。該函數(shù)可寫可不寫,因?yàn)閠hen中的第二個(gè)函數(shù)也可以作為狀態(tài)失敗調(diào)用的函數(shù)苛萎。不過如果邏輯不是很清晰的話桨昙,可以讓then()專門返回成功狀態(tài),catch()專門返回失敗狀態(tài)腌歉。所以前面的代碼可以寫成:
let isRun = true;
? ? ? ? let demo = new Promise((resolve,reject)=> {
? ? ? ? ? ? if (isRun) {
? ? ? ? ? ? ? ? resolve('成功蛙酪!');
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? reject();
? ? ? ? ? ? }
? ? ? ? })
? ? ? ? demo.then(
? ? ? ? ? ? (res) => {
? ? ? ? ? ? ? ? console.log(res);
? ? ? ? ? ? }
? ? ? ? ).catch(
? ? ? ? ? ? (err) => {
? ? ? ? ? ? ? ? console.log('失敗了');
? ? ? ? ? ? }
? ? ? ? )
這里是用鏈?zhǔn)浇Y(jié)構(gòu)寫的,不會(huì)的可以查一下什么是鏈?zhǔn)浇Y(jié)構(gòu)翘盖,或者直接分開寫桂塞。
p.s.這里說一下還有個(gè)finally函數(shù),就是在promise執(zhí)行完畢(無論成功與否)后調(diào)用的函數(shù)馍驯,但我查了一下阁危,該函數(shù)并被標(biāo)準(zhǔn)函數(shù)玛痊,我也不知道是否支持,所以就不寫了狂打,感興趣的可以查一下擂煞。
封裝Promise
let getPromise = (demo) => {
? ? ? ? ? ? return new Promise((resolve,reject) => {
? ? ? ? ? ? ? ? if (demo) {
? ? ? ? ? ? ? ? ? ? resolve('成功');
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? reject('失敗')
? ? ? ? ? ? ? ? }
? ? ? ? ? ? })
? ? ? ? }
let demo = getPromise(true)
? ? ? ? demo.then(
? ? ? ? ? ? (res) => {
? ? ? ? ? ? ? ? console.log(res);
? ? ? ? ? ? }
? ? ? ? )
這里就是普遍的寫法,看到這里給我說看不懂的建議死刑
ok趴乡,到這里應(yīng)該就差不多对省,基本的寫法是已經(jīng)有了,如果是小白只想理解promise是啥的晾捏,看到這里就行了官辽,如果是正兒八經(jīng)學(xué)習(xí)的,那可以繼續(xù)看一下粟瞬。
async[?'z??k]和await(暫時(shí)簡寫)
async/await是什么
async/await 是ES7提出的基于Promise的解決異步的最終方案同仆。
async
async是一個(gè)加在函數(shù)前的修飾符,被async定義的函數(shù)會(huì)默認(rèn)返回一個(gè)Promise對象resolve的值裙品。因此對async函數(shù)可以直接then俗批,返回值就是then方法傳入的函數(shù)。
await
await 也是一個(gè)修飾符市怎,只能放在async定義的函數(shù)內(nèi)岁忘。可以理解為等待区匠。
await 修飾的如果是Promise對象:可以獲取Promise中返回的內(nèi)容(resolve或reject的參數(shù))干像,且取到值后語句才會(huì)往下執(zhí)行;
如果不是Promise對象:把這個(gè)非promise的東西當(dāng)做await表達(dá)式的結(jié)果驰弄。
async/await 的正確用法