因為疫情的原因,這是最長的一個假期了,人也變懶惰了些。
單執行緒
一個執行緒就是一個處理任務的一個基本過程,可以這樣理解:排隊取號的過程就是一個執行緒,而單執行緒的意思就是,你必須等你前面的人完成了自己的事兒,才能輪到你。
Task1 --> Task2 --> Task3
複製程式碼
單執行緒特點是:任務依次執行,後面的必須等前面的任務完成後,才能執行下一個任務。
JS 單執行緒
JS 程式碼被JS引擎執行的時候是單執行緒的,同一時刻有且僅有一處程式碼正在執行,同一個時間只能做一件事,並阻塞其它的程式碼。
如下程式碼
function Task1() {
//一個耗時5s的任務
console.log("任務1完成了")
}
function Task2() {
console.log("任務2完成了")
}
function Task3() {
console.log("任務3完成了")
}
Task1()
Task2()
Task3()
複製程式碼
結果會按照 Task1,Task2,Task3的順序列印到控制檯。 單執行緒就意味著,Task2必須等Task1完成後,才會被執行,哪怕Task1需要很長的時間才會執行完成。
同步和非同步
因為JS在被執行的時候是單執行緒的,像前面一樣,如果Task1需要很久才能出結果,這樣後面的任務只能一直等,這樣就會導致後面的任務都不會被執行,導致頁面卡住不懂。那如何解決這樣的問題呢?
答案就是非同步。
先看一段程式碼:
function Task1() {
setTimeout(function(){
console.log("任務1完成了")
},0)
}
function Task2() {
console.log("任務2完成了")
}
function Task3() {
console.log("任務3完成了")
}
Task1()
Task2()
Task3()
複製程式碼
這段程式碼的執行結果是 Task2,Task3,Task1的順序,因為Task1 是非同步任務,後面的任務不會等Task1的結果。
再看一個例子 我們使用AJAX 發請求的時候,一個請求也可能很快就有結果,也很有可能需要很久才能得到結果。
- 同步的AJAX
// 同步AJAX
function taskB(){
var result = $.ajax({
url:"/data.json",
async: false // 同步
})
return result
}
taskA()
taskB() // 可能要很久才能完成
taskC()
複製程式碼
我們將AJAX 設定成同步的,這就意味者,後面的任務必須等這個AJAX的結果到來後,才能夠繼續向下執行。這就導致頁面會卡住。
如何解決呢?就是使用非同步的AJAX
- 非同步的AJAX
// 同步AJAX
function taskB(){
var result = $.ajax({
url:"/data.json",
async: true // 非同步
})
return result
}
taskA()
taskB() // 可能要很久才能完成
taskC() // 不等TaskB 的執行結果,直接執行TaskC
複製程式碼
現在,TaskC不需要等TaskA完成後才會被執行,這樣頁面就不會被卡住。
這似乎有點問題,因為前面說了JS在被執行的時候,是單執行緒的,同一個時刻只有只有一處程式碼被執行,那是怎麼做到了,直接跳過TaskB,而直接執行後面的呢?TaskB 任務又是誰在執行呢?答案就是,這些非同步任務是瀏覽器的其他模組完成的,比如AJAX的請求就是由瀏覽器的網路模組去處理。
也就是說非同步的任務,是由瀏覽器的其他執行緒去完成的。
回撥
因為非同步的結果需要一段時間才能夠獲得,那麼你怎麼知道它什麼時候有結果呢?怎麼獲取到這個非同步的結果呢? 一般獲取非同步的結果有兩種方式:
- 輪詢
- 回撥
先不說什麼是回撥,看程式碼
// 非同步任務
function buyFruit(f) {
setTimeout(function(){
f("買到的蘋果")
},3000)
}
// 處理非同步結果的函式
function eat(fruit) {
console.log(fruit)
}
// 非同步任務是買水果,任務的結果用回撥函式去處理
buyFruit(eat)
複製程式碼
上面的程式碼中,有一個非同步任務buyFruit,那我如何在他買到水果後再進行其他操作呢,比如我需要吃買到的水果,可以這樣做,將eat函式當作buyFruit函式的一個引數傳進去即可,這樣當buFruit有結果的時候,eat就可以對這個非同步結果進行處理了,這裡,eat函式就回撥。
回撥是什麼?也許你看過各種概念,被搞的暈頭轉向,還有舉的各種形象的例子。其實,我覺得很多東西不要去理解概念,你知道它是什麼,它的作用是什麼,這些概念其實沒什麼作用,如果你非要問什麼是回撥,首先,回撥是函式,這個函式被當作一個引數傳給另一個函式。就這麼簡單。
用回撥函式獲取非同步的結果,存在一些問題,比如,當你還有更多的非同步操作後,會很難處理,這就出現了一些其他的方法解決,比如Promise。
小結
簡單溫習了一下JS的單執行緒和非同步:
- 單執行緒的概念:任務依次順序執行。
- 單執行緒的缺點:會阻塞後面的任務執行。
- 非同步解決阻塞,非同步由瀏覽器其他執行緒處理。
- 回撥的概念和用法。
疫情快快結束啊,這個假也太長了一點吧。。