1琳拭、準(zhǔn)備知識
1训堆、回調(diào)函數(shù):
理解:一個函數(shù),自己定義的白嘁,自己沒有調(diào)用坑鱼,但是函數(shù)執(zhí)行了。
同步回調(diào):立即執(zhí)行絮缅,完全執(zhí)行完才結(jié)束姑躲,不會放到回調(diào)隊列中
?例子: 數(shù)組遍歷的forEach()還有promise的excutor
異步回調(diào):不會被立即執(zhí)行,會被放到回調(diào)函數(shù)中將來執(zhí)行
例子:定時器回調(diào)盟蚣、ajax回調(diào)黍析、promise的成功回調(diào)onResolve和失敗回調(diào)onReject
?2、錯誤類型
*Error:所有錯誤的父類型
ReferenceError:引用變量不存在屎开,打印一個未聲明的變量會觸發(fā)此錯誤
TypeError:數(shù)據(jù)類型不正確阐枣,將一個一般類型的變量當(dāng)成函數(shù)調(diào)用會觸發(fā)此錯誤
RangerError:數(shù)據(jù)值不在允許的方范圍,一個遞歸沒有跳出條件,遞歸會不斷執(zhí)行最后將棧占滿
SyntaxError:語法錯誤
*錯誤處理
捕獲錯誤:try...catch()? ?使代碼不會因為報錯而停止執(zhí)行
拋出錯誤:throw error 拋出的錯誤可以用try...catch()來接收
2奄抽、Promise
1蔼两、promise是什么:
promise是js中進(jìn)行異步編程的新的解決方案
具體表達(dá):
從語法上來說:promise是一個構(gòu)造函數(shù)
從功能上說:promise對象用來封裝一個異步操作并可以獲取其結(jié)果
2、promise狀態(tài):
pedding:初始狀態(tài)
resolve:成功狀態(tài)
reject:失敗狀態(tài)
3逞度、promise狀態(tài)的改變:
pending變?yōu)閞esolved
pending變?yōu)閞ejected
說明?:?只有這兩種额划,且一個promise對象只能改變一次
無論成功還是失敗,都只會由一個數(shù)據(jù)結(jié)果
成功的結(jié)果數(shù)據(jù)一般稱為value档泽,失敗的結(jié)果一般成為reason
4俊戳、promise包含的內(nèi)容:
promise構(gòu)造函數(shù):Promise(excutor{})
excutor函數(shù):同步執(zhí)行(resolve,reject)=>{}
resolve函數(shù):內(nèi)部定義成功時我們調(diào)用的函數(shù)?value=>{}
reject函數(shù):內(nèi)部定義失敗時我們調(diào)用的函數(shù)?reason=>{}
說明:excutor會在promise內(nèi)部立即同步回調(diào),異步操作在執(zhí)行器中執(zhí)行
4馆匿、promise的基本使用:
Promise是一個構(gòu)造函數(shù)抑胎,構(gòu)造函數(shù)的參數(shù)是一個函數(shù)即excutor(同步函數(shù)),該函數(shù)用來修改promise的狀態(tài)可以是pedding->resolve成功渐北,pedding->reject失敗阿逃。然后可以執(zhí)行.then()函數(shù)用來處理成功或者失敗的回調(diào)
5、promise的好處
1、指定回調(diào)函數(shù)的方式更加靈活:
舊的:必須在啟動異步任務(wù)前指定
?promise:?啟動異步任務(wù)==>返回promise對象=>給psomise對象綁定回調(diào)函數(shù)(甚至可以在異步任務(wù)執(zhí)行結(jié)束后指定)
2恃锉、支持鏈?zhǔn)秸{(diào)用?可以很好地解決回調(diào)地獄問題
什么是回調(diào)地獄:回調(diào)函數(shù)的嵌套調(diào)用搀菩,外部回調(diào)函數(shù)異步執(zhí)行的結(jié)果是嵌套回調(diào)函數(shù)執(zhí)行的條件
回調(diào)地獄的缺點(diǎn):不便于閱讀/不便于異步處理
6、Promise的基本方法
1破托、promise.prototype.then方法:(onResolved肪跋,onRejected)=>{}
onResolved函數(shù):成功的回調(diào)函數(shù)(value)=>{}
onRjected函數(shù):失敗的回調(diào)函數(shù)(reason)=>{}
說明:指定用于得到成功的value的成功回調(diào)和用于得到失敗的reason的失敗回調(diào)
返回一個新的promise對象
2、promise.prototype.catch方法:(onRejected)=>{}
onRejected函數(shù):失敗的回調(diào)函數(shù)(reason)=>{}
說明:相當(dāng)于then(undefined,onRejected)
3炼团、promise.resolve方法:(value)=>{}
value:成功的數(shù)據(jù)或promise對象
說明:返回一個成功/失敗的promise對象
?4、promise.reject方法:(reason)=>{}
?value:失敗的原因
?說明:返回失敗的promise對象
5疏尿、promise.all()方法:(promises)=>{}
promises:包含n個promise的數(shù)組
說明:返回一個新的promise瘟芝,只有所有的Prmise成功才成功,只要有一個失敗就直接失敗
6褥琐、promise.race()方法:(promises)=>{}
promises:包含n個promise的數(shù)組
說明:返回一個新的promise锌俱,第一個完成promise的結(jié)果狀態(tài)就是最終的結(jié)果
6、自定義promise之前的幾個關(guān)鍵問題
1敌呈、promise的狀態(tài)如何改變
resolve(value):如果當(dāng)前是pedding就會變成resolve
reject(reason):如果當(dāng)前是pedding那么就會變成reject
拋出異常:如果當(dāng)前是pedding就會變?yōu)閞eject
2贸宏、改變promise狀態(tài)和指定回調(diào)函數(shù)誰先誰后
(1)都有可能,正常情況下是先指定回調(diào)函數(shù)在改變狀態(tài),但是可以先改變狀態(tài)在指定回調(diào)
(2)如何先改變狀態(tài)在指定回調(diào)
? ? ?在執(zhí)行器中調(diào)用resolve()/reject()
? ? ? 延遲更長時間再調(diào)用then()
(3)什么時候才能得到數(shù)據(jù)
? ? ?如果先指定回調(diào)函數(shù),那么在狀態(tài)方法改變時磕洪,回調(diào)函數(shù)就會調(diào)用吭练,得到數(shù)據(jù)
? ? ? 如果先改變狀態(tài),那么當(dāng)指定回調(diào)時析显,回調(diào)函數(shù)就會調(diào)用鲫咽,得到數(shù)據(jù)
3、關(guān)于promise的then方法返回promise對象的狀態(tài)
promise.then()返回的新promise的結(jié)果狀態(tài)由什么決定谷异?
(1)簡單表達(dá):由then()指定的回調(diào)函數(shù)執(zhí)行的結(jié)果決定
(2)詳細(xì)表達(dá):
*如果拋出異常:新的promise變?yōu)閞ejected,reason為拋出的異常?
*如果返回的是一個非promise的任意值分尸,新promise變?yōu)閞esolved,value為返回的值歹嘹,如果沒有返回結(jié)果那么相當(dāng)于return undefined?
*如果返回的是另一個新的promise箩绍,此時promise的結(jié)果就會成為新的promise的結(jié)果
4、promise如何進(jìn)行串聯(lián)的多個任務(wù)操作
(1)promise的then()返回一個新的promise尺上,可以實(shí)現(xiàn)then的鏈?zhǔn)秸{(diào)用
(2)通過then的鏈?zhǔn)秸{(diào)用串聯(lián)多個同步/異步任務(wù)
5材蛛、promise異常穿透
(1)當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用時,可以在最后面指定失敗的回調(diào)
(2)前面任何操作出了異常怎抛,都會傳到最后失敗的回調(diào)中去
中斷promise鏈
(1)當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用時仰税,在中間中斷,不在調(diào)用后面的回調(diào)函數(shù)
(2)辦法:在回調(diào)函數(shù)中返回一個pendding狀態(tài)的promise對象
7抽诉、自定義的promise
1陨簇、promsie是一個構(gòu)造函數(shù)并且接受一個函數(shù)(excutor)作為參數(shù),這個函數(shù)是同步執(zhí)行的,該函數(shù)又接收兩個函數(shù)作為參數(shù)resolve(),reject()河绽。代碼實(shí)現(xiàn):
2己单、一個promise應(yīng)該有的數(shù)據(jù):狀態(tài)(pedding,resolve,reject),傳遞的數(shù)據(jù)耙饰,用于存儲then中的回調(diào)函數(shù)的數(shù)組纹笼。為什么要設(shè)置這個數(shù)組,因為我們前面討論過promise修改狀態(tài)和指定回調(diào)函數(shù)順序的問題(問題2)苟跪,如果先指定回調(diào)函數(shù)在修改狀態(tài)那么此時應(yīng)該將回調(diào)函數(shù)存儲起來廷痘,以便修改過狀態(tài)之后直接調(diào)用。代碼實(shí)現(xiàn):
3件已、resolve和reject函數(shù)所做的工作:修改狀態(tài)(只修改一次)笋额,將傳遞的數(shù)據(jù)保存,如果回調(diào)函數(shù)已經(jīng)指定那么執(zhí)行回調(diào)函數(shù)篷扩。代碼實(shí)現(xiàn):
4兄猩、如果promise拋出一個錯誤那么他將會執(zhí)行reject函數(shù),即問題1的第三點(diǎn)鉴未,代碼實(shí)現(xiàn):
5枢冤、then函數(shù)執(zhí)行以下幾種情況需要考慮:狀態(tài)是否已經(jīng)發(fā)生改變,如果改變直接執(zhí)行onResolved函數(shù)铜秆,如果沒有改變那么將onResolved函數(shù)和onRejected函數(shù)壓入callback數(shù)組中淹真,代碼實(shí)現(xiàn):
6、關(guān)于promise的then方法返回promise對象的狀態(tài)即問題3连茧,如果回調(diào)函數(shù)返回是promise趟咆,那么return的那個promise結(jié)果就是要向下傳遞的結(jié)果。這種情況在原裝的promise中是以return?new?promise.resolve(value)的形態(tài)呈現(xiàn)梅屉。
要想知道返回的是否成功必須取回promise的值值纱,因此用then的方法來獲取promise的值以及狀態(tài)
?如果成功說明原裝代碼為return?new?promise.resolve(value),返回的下一個狀態(tài)也應(yīng)該是成功坯汤,所以調(diào)用resolve
?如果失敗說明原裝代碼為return?new?promise.reject(reason)虐唠,返回的下一個狀態(tài)也應(yīng)該是失敗,所以調(diào)用reject
實(shí)現(xiàn)代碼:
7惰聂、如果then函數(shù)中不指定onResolved函數(shù)疆偿,onRejected函數(shù)時,promise有默認(rèn)的操作搓幌,如果是不指定onResolved函數(shù)杆故,那么把上面的value值繼續(xù)向下傳遞,如果不指定onRejected函數(shù)那么拋出一個錯誤溉愁。代碼實(shí)現(xiàn):
完整代碼:https://github.com/wangczc1234/Promise
最后歡迎大家投遞
字節(jié)跳動校招內(nèi)推碼: 2XVEJNC
校招投遞鏈接: https://jobs.toutiao.com/s/djchQRf
社招投遞鏈接: https://job.toutiao.com/s/djc2b4C