一、什么是回呼函式?回呼函式有什么缺點?如何解決回呼地獄問題?
-
回呼函式概念
- 回呼函式是一個作為變數傳遞給另一個函式的函式,它在主體函式執行完之后再執行
-
回呼函式特點
- 你定義的
- 你沒有呼叫
- 但是最終執行了
-
回呼函式可能的缺點
層層嵌套的異步函式的操作叫做回呼地獄
- 容易寫出回呼地獄
- 不能使用 try catch 捕獲錯誤
- 不能直接 return
-
常見的回呼函式
- DOM事件回呼函式
- 定時器回呼函式
- ajax請求回呼函式
- 生命周期回呼函式
-
如何解決回呼地獄
- promise
- async / await
- generator
二、異步編程的實作方式
1.回呼函式的方式
- 使用回呼函式的方式有一個缺點是,多個回呼函式嵌套的時候會造成回呼函式地獄,上下兩層的回呼函式間的代碼耦合度太高,不利于代碼的可維護,
2.Promise的方式
- 使用 Promise 的方式可以將嵌套的回呼函式作為鏈式呼叫,但是使用這種方法,有時會造成多個 then 的鏈式呼叫,可能會造成代碼的語意不夠明確,
3.generator的方式
- 它可以在函式的執行程序中,將函式的執行權轉移出去,在函式外部還可以將執行權轉移回來,當遇到異步函式執行的時候,將函式執行權轉移出去,當異步函式執行完畢時再將執行權給轉移回來,因此在 generator 內部對于異步操作的方式,可以以同步的順序來書寫,使用這種方式需要考慮的問題是何時將函式的控制權轉移回來,因此需要有一個自動執行 generator 的機制,比如說 co 模塊等方式來實作 generator 的自動執行,
4.async函式的方式
- async 函式是 generator 和 promise 實作的一個自動執行的語法糖,它內部自帶執行器,當函式內部執行到一個 await 陳述句的時候,如果陳述句回傳一個 promise 物件,那么函式將會等待 promise 物件的狀態變為 resolve 后再繼續向下執行,因此可以將異步邏輯,轉化為同步的順序來書寫,并且這個函式可以自動執行,
三、對Promise的理解
在構造 Promise 的時候,建構式內部的代碼是立即執行的
-
Promise本身是同步的立即執行函式,當在executor中執行 resolve() 或者 reject() 的時候, 此時是異步操作,也就是說promise中函式體內部的非異步操作正常順序執行,resolve() 和 reject() 異步操作為promise實體物件的回傳結果,這個回傳結果后面的then或者catch需要用,所以then和catch要放到異步任務中等待所有同步任務執行完畢之后再按順序(或者如果有定時器,需要遵循定時器的時間)執行,
-
Promise是異步編程的一種解決方案,它是一個物件,可以獲取異步操作的訊息,他的出現大大改善了異步編程的困境,避免了地獄回呼,它比傳統的解決方案回呼函式和事件更合理和更強大,所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,從語法上說,Promise 是一個物件,從它可以獲取異步操作的訊息,Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理,
-
Promise 物件是異步編程的一種解決方案,最早由社區提出,Promise 是一個建構式,接收一個函式作為引數,回傳一個 Promise 實體,一個 Promise 實體有三種狀態,分別是pending、resolved 和 rejected,分別代表了進行中、已成功和已失敗,實體的狀態只能由 pending 轉變 resolved 或者rejected 狀態,并且狀態一經改變,就凝固了,無法再被改變了,狀態的改變是通過 resolve() 和 reject() 函式來實作的,可以在異步操作結束后呼叫這兩個函式改變 Promise 實體的狀態,它的原型上定義了一個 then 方法,使用這個 then 方法可以為兩個狀態的改變注冊回呼函式,這個回呼函式屬于微任務,會在本輪事件回圈的末尾執行,
-
Promise的實體有三個狀態
當把一件事情交給promise時,它的狀態就是Pending,任務完成了狀態就變成了Resolved、沒有完成失敗了就變成了Rejected
- Pending(進行中)
- Resolved(已完成)
- Rejected(已拒絕)
-
Promise的實體有兩個程序
一旦從進行狀態變成為其他狀態就永遠不能更改狀態了
- pending -> fulfilled : Resolved(已完成)
- pending -> rejected:Rejected(已拒絕)
-
Promise的特點
- 物件的狀態不受外界影響,promise物件代表一個異步操作,有三種狀態,pending(進行中)、fulfilled(已成功)、rejected(已失敗),只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,這也是promise這個名字的由來——“承諾”,
- 一旦狀態改變就不會再變,任何時候都可以得到這個結果,promise物件的狀態改變,只有兩種可能:從pending變為fulfilled,從pending變為rejected,這時就稱為resolved(已定型),如果改變已經發生了,你再對promise物件添加回呼函式,也會立即得到這個結果,這與事件(event)完全不同,事件的特點是:如果你錯過了它,再去監聽是得不到結果的,
-
Promise的缺點
- 無法取消Promise,一旦新建它就會立即執行,無法中途取消
- 如果不設定回呼函式,Promise內部拋出的錯誤,不會反應到外部
- 當處于pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)
四、Promise解決了什么問題
解決了地獄回呼的問題
五、Promise的基本用法
1.創建Promise物件
- new Promise() 方法
- promise.resolve() 方法
- promise.reject() 方法
2.Promise方法
- then() 方法
- catch() 方法
- all() 方法
- race() 方法
- finally() 方法
六、Promise.all和Promise.race的區別的使用場景
1.Promise.all()
- Promise.all可以將多個Promise實體包裝成一個新的Promise實體,同時,成功和失敗的回傳值是不同的,成功的時候回傳的是一個結果陣列,而失敗的時候則回傳最先被reject失敗狀態的值,Promise.all中傳入的是陣列,回傳的也是是陣列,并且會將進行映射,傳入的promise物件回傳的值是按照順序在陣列中排列的,但是注意的是他們執行的順序并不是按照順序的,除非可迭代物件為空,需要注意,Promise.all獲得的成功結果的陣列里面的資料順序和Promise.all接收到的陣列順序是一致的,這樣當遇到發送多個請求并根據請求順序獲取和使用資料的場景,就可以使用Promise.all來解決,
2.Promise.race()
- Promse.race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])里面哪個結果獲得的快,就回傳那個結果,不管結果本身是成功狀態還是失敗狀態,當要做一件事,超過多長時間就不做了,可以用這個方法來解決,
七、對async/await 的理解
- async/await其實是Generator 的語法糖,它能實作的效果都能用then鏈來實作,它是為優化then鏈而開發出來的,從字面上來看,async是“異步”的簡寫,await則為等待,所以很好理解async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執行完成,
- async函式回傳的是一個Promise 物件,如果在函式中 return 一個直接量,async 會把這個直接量通過 Promise.resolve() 封裝成 Promise 物件,async 函式回傳的是一個 Promise 物件,所以在最外層不能用 await 獲取其回傳值的情況下,當然應該用原來的方式:then() 鏈來處理這個 Promise 物件,
八、await 到底在等什么
- await后面必須是異步函式, await是在等待一個異步函式完成,而這個異步函式回傳值可能時promise物件,也可能是其他值,而await 等待的就是就是異步函式的回傳值,
- 如果它等到的不是一個 Promise 物件,那 await 運算式的運算結果就是它等到的東西,
- 如果它等到的是一個 Promise 物件,await 就忙起來了,它會阻塞在async函式之中且await后面的代碼,等著 Promise 物件 resolve,然后得到 resolve 的值,作為 await 運算式的運算結果,
九、async/await的優勢
- Promise 通過 then 鏈來解決多層回呼的問題,而 async/await 來進一步優化promise的 then() 方法的多層呼叫,
- Promise傳遞中間值?常麻煩,?async/await?乎是同步的寫法,?常優雅 ,
- 錯誤處理友好,async/await可以?成熟的try/catch,Promise的錯誤捕獲?常冗余,
- 除錯友好,Promise的除錯很差,由于沒有代碼塊,你不能在?個回傳運算式的箭頭函式中設定斷點,如果你在?個.then代碼塊中使?除錯器的步進(step-over)功能,除錯器并不會進?后續的.then代碼塊,因為除錯器只能跟蹤同步代碼的每?步,
十、async/await 如何捕獲例外
try...catch...
十一、setTimeout、Promise、Async/Await 的區別
1.setTimeout
-
定時器是異步任務,會將定時器中的代碼放到異步任務中,待頁面中所有同步任務執行完畢之后再執行異步任務佇列,
// 例如 console.log('script start') setTimeout(function () { console.log('setTimeout') }, 0) console.log('script end') // 輸出順序:script start --> script end --> setTimeout
2.Promise
-
Promise本身是同步的立即執行函式, 當在executor中執行resolve或者reject的時候, 此時是異步操作,會先執行promise中的同步任務,然后執行promise之外的同步操作(按照書寫代碼的先后順序),而promise.then( )視為異步任務的方法,會加入到任務佇列中,等待全部同步任務執行完畢再按順序執行異步任務佇列中的任務,promise后面的定時器也是異步函式,也要加入到異步函式佇列中,即使定時器是0s,而且按照代碼書寫先后順序,在任務佇列中會排到then后面,
-
new Promise():類似于同步,先微任務( Promise、async / await )再宏任務( 定時器、Ajax、DOM事件 )
// 例如 console.log('script start') let promise1 = new Promise(function (resolve) { console.log('promise1') resolve() console.log('promise1 end') }).then(function () { console.log('promise2') }) setTimeout(function () { console.log('setTimeout') }, 0) console.log('script end') // 輸出順序:script start --> promise1 --> promise1 end --> script end --> promise2 --> setTimeout
3.async / await
-
async函式為異步函式,回傳的也是promise物件,所以說async函式也是立即執行函式,他里面的代碼會按照順序相繼執行;但當有異步任務,且異步任務前面有await時,這時await若未等到異步任務的結果,會阻礙async里面且在await下面的代碼(await后面緊跟著的異步任務會正常執行),執行async函式下面的代碼直至await等到結果之后再執行它下面在async函式中的代碼,
// 例如 async function async1 () { console.log('async1 start') await async2() console.log('async1 end') } async function async2 () { console.log('async2') } console.log('script start') async1() console.log('script end') // 輸出順序:script start --> async1 start --> async2 --> script end --> async1 end
十二、并發與并行的區別
1.并發
- 并發是宏觀概念,在一段時間內通過任務間的切換完成了這些任務,這種情況就可以稱之為并發(指在同一時刻只能有一條指令執行,但多個行程指令被快速的輪換執行),

2.并行
- 并行是微觀概念,指在同一時刻,有多條指令在多個處理器上同時執行,同時完成多個任務的情況就可以稱之為并行,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/539175.html
標籤:JavaScript
