導讀
首先,要知道JavaScript是一門單執行緒的語言,要搞明白其為何會設計成單執行緒,要先來說一下JavaScript的最初應用場景,
其次,在單執行緒語言中如何處理多執行緒的任務,
再次,同步和異步的流程以及如何理解異步,
然后,在解決復雜的邏輯業務時,出現了什么樣的問題,
再然后,怎樣解決這一問題,
=> Promise/.then(),async/await,
最后談談微任務及宏任務
JavaScript最初的應用場景
最初,JavaScript的設計是作為瀏覽器腳本語言實作用戶的互動,而為了避免多執行緒給我們帶來很多不必要的麻煩,比如說:一個執行緒在洗掉一個節點,而另一個執行緒在修改這個節點,這時我們應該以哪一條執行緒為主呢?
因此,設計者將其設計成單執行緒的語言,
在H5中規定了JS可以擁有多個子執行緒,但是子執行緒仍然是依托于主執行緒的,且不能夠操作節點,
為什么要使用多執行緒
-
單執行緒的缺點:
單執行緒有一個“致命”的缺點,就是會造成阻塞;
因為是單執行緒,所以在程式運行時是按照先進先出的原則來進行任務處理的,也正是因如此,在主執行緒遇到了耗時操作后,其后的任務就進入到了等待的狀態,如果此時CPU是被占用的,也沒什么,但是如果這個耗時任務是一個不占CPU的操作,舉個栗子:向服務端請求資料,這個時候CPU出入空閑狀態但是程式并沒有執行結束,這就形成了阻塞,
-
啟發:
在進行耗時操作且影響代碼正常運行時,我們可以先不管這個操作,將其掛起,先處理后面的任務,等到主執行緒清空時,再來執行這個任務,于是出現了同步任務和異步任務,
同步和異步及程式運行流程
關于這一塊內容,筆者建議從整體來看,將這一塊中的內容結合起來讀,可能會更好理解
-
我們可以將同步任務理解為在主執行緒中執行的任務,異步任務理解為在子執行緒執行,
-
同步任務和異步任務的執行程序:
-
同步任務正常運行,沒有特殊情況會一直執行完畢;
-
當主執行緒運行到異步任務時,會安排一個子執行緒去運行異步任務,當異步任務運行結束后,向任務佇列發送一個事件,表示該異步任務可以進入主執行緒執行了,
-
-
當不考慮下面講的微任務和宏任務時,我們的程式運行時,會先執行同步任務,執行到異步任務后,將其發送到子執行緒中運行,運行結束會向任務佇列發送一個事件,同步任務執行完畢即主執行緒清空后,主執行緒會向任務佇列詢問,是否有接收到事件,如果沒有,那么主執行緒會一直詢問,這個程序稱為
event loop;如果有,就執行這個事件,直到程式全部完成,
事件
在上文我們提到了事件這一概念,可以將事件理解為異步任務回傳的一個回呼函式,這個回呼函式也就是事件會在主執行緒上運行,異步任務必須有回呼函式,
拓展:異步函式必須return一個Promise物件
關于事件,阮一峰前輩是這么寫的:
"任務佇列"中的事件,除了IO設備的事件以外,還包括一些用戶產生的事件(比如滑鼠點擊、頁面滾動等等),只要指定過回呼函式,這些事件發生時就會進入"任務佇列",等待主執行緒讀取,
“回呼地獄”
在實際開發中,為了實作一些邏輯需求,可能會用到多層回呼函式嵌套,這個時候會導致代碼的可讀性很差,人們稱之為“回呼地獄”
Promise物件
-
代表的是異步操作 最終完成或失敗
-
目的:將回呼函式的多層嵌套形式,拆解成鏈式呼叫的形式,
-
本質:函式回傳的物件,在這個物件上系結回呼函式,避免從一開始將回呼函式作為引數傳入上一層函式,
-
一個Promise必然會處于這幾種狀態:
-
待定(pending):初始狀態,既沒有被兌現,也沒有被拒絕
-
已兌現(fulfilled):意味著操作成功完成 resolve
-
已拒絕(rejected):意味著操作失敗 reject
-
-
Promise的使用:一般作為函式的回傳值
const fn = function(){ return new Promise((resolve,reject)=>{ if(ture){ resolve(a); }else{ reject(b); } }) } ? fn() .then((res)=>{有回傳值的函式}) .then((res)=>{有回傳值的函式}) .then((res)=>{有回傳值的函式}) ... .then(res=>{最后的函式}) // 如果Promise物件中的請求完成了,那么將resolve的值傳給then中的回呼函式作為引數執行then方法 // 可以附加 .catch()在鏈式結構的末尾,來捕獲錯誤(reject傳回的值),并且之后的then不會執行 // 可以在最后加一個 .finally() 來執行清理操作 并且這個方法不管請求成功與否都會執行
async/await
是Promise的語法糖;讓繁瑣的then(),和冗長的鏈式呼叫可讀性變得更長些;
具體使用方式:
//異步函式1
function getData(data){
return new Promise((reslove)=>{
reslove(data)
})
}
//異步函式2
function sayHello(data){
return new Promise((reslove)=>{
reslove(data)
})
}
?
//異步函式
async function fn(){
// await相當于.then() getData()相當于是回呼函式
// await必須在async修飾的函式體內使用
const promiseA = await getData('info')
const promiseB = await sayHello(promiseA);
console.log(promiseB)
}
談談微任務和宏任務
微任務
-
注意:Promise物件中的代碼是同步的,then()方法中的回呼函式才是異步的
-
then()中的是微任務
宏任務
-
定時器是宏任務
代碼執行順序口訣:先同步后異步,先微任務后宏任務
總之,同微宏
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/390373.html
標籤:其他
