關於 js 中的回撥函式 callback

cayley的程式設計之路發表於2019-03-04

關於 js 中的回撥函式 callback

本文寫於1年前 曾經的學習文章如今拿出來分享

前言

其實我一直很困惑關於js中的callback,困惑的原因是,學習中這塊看的資料少,但是平時又經常見,偶爾複製一下前人程式碼,功能實現了也就不再去追其原由,這麼著,這個callback的概念就越來越混亂,因為你總感覺它是你Ajax請求後呼叫的那個函式,又感覺它是你某一個函式中的形參而已,而當你有一天看到一點關於Node.js的程式碼後你會更加崩潰,因為你會發現很多的callback,但是這麼著下去肯定是不行的,因為很多的東西如果只是知道概念和理論,沒有實踐出結果,沒有思考和感受,這些東西永遠不是你的,所以任何關於技術上用到的東西都應該去花時間鑽研一下,學習 付出時間 實踐都會搞明白的,還會沉澱很多思想,所以最近一直在瀏覽相關的文章和資料,自己在專案中也用到了一些去實踐,這樣一輪下來後,你會發現明亮了很多

一 .搞清楚非同步和同步

非同步async/同步sync

舉個小栗子

1.早上起來不論你是先刷牙還是先洗臉,都要等一個事情完畢後才能進行下一項,這就是一個同步的例子

2.然後刷牙的時候你也可以燒水喝 (不用等你刷完牙)這就是一個非同步的例子

來段非同步程式碼示例

關於 js 中的回撥函式 callback

js裡面最基礎的非同步實現

關於 js 中的回撥函式 callback

執行結果

以上程式碼會先執行函式a,而且不會等到a中的延遲函式執行完才執行函式b, 在延遲函式被觸發的過程中就執行了函式b,當js引擎的event 佇列空閒時才會去執行佇列裡等待的setTimeout的回撥函式,這就是一個非同步的例子

題外話

呼叫 setTimeout 函式會在一個時間段過去後在佇列中新增一個訊息。這個時間段作為函式的第二個引數被傳入。如果佇列中沒有其它訊息,訊息會被馬上處理。但是,如果有其它訊息,setTimeout 訊息必須等待其它訊息處理完。因此第二個引數僅僅表示最少的時間 而非確切的時間

所以即使,時間設定為0,也是會照樣先執行函式b

來段同步程式碼示例

關於 js 中的回撥函式 callback

執行結果為1

print函式會等change函式完成之後去執行,所以結構輸出為1,因為change函式修改了全域性變數a的值,change執行之後才執行的print函式

二.回撥函式到底是什麼

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.

以上解釋是Google得出的解釋,非常清晰簡明,有時候我覺得英文理解要比翻譯成中文二次理解更清楚

來看幾個經典的回撥函式程式碼,我敢保證你一定用過他們

關於 js 中的回撥函式 callback

非同步請求的回撥函式

關於 js 中的回撥函式 callback

點選事件的回撥函式

關於 js 中的回撥函式 callback

陣列中遍歷每一項呼叫的回撥函式

關於 js 中的回撥函式 callback

同步回撥的例子

所以回撥與同步、非同步並沒有直接的聯絡,回撥只是一種實現方式,既可以有同步回撥,也可以有非同步回撥,還可以有事件處理回撥和延遲函式回撥,這些在我們工作中有很多的使用場景

所以其實並不是我們不認識回撥函式,而是我們都縈繞在了這個“callback“ 這個詞上,當你在一個函式中看到它是就會困惑,其實它只是一個形參名字而已

三.為什麼寫回撥函式

看了以上的簡單介紹之後,是不是對callback不再陌生和覺得神祕,所以盡情的去使用吧,

1.關於回撥函式和js單執行緒以及js非同步機制

我們都知道js是單執行緒的,這種設計模式給我們帶來了很多的方便之處,我們不需要考慮各個執行緒之間的通訊,也不需要寫很多燒腦的程式碼,也就是說js的引擎只能一件一件事的去完成和執行相關的操作,所以所有需要執行的事情都像排隊一樣,等待著被觸發和執行,可是如果這樣的話,如果在佇列中有一件事情需要花費很多的時間,那麼後面的任務都將處於一種等待狀態,有時甚至會出現瀏覽器假死現象,例如其中有一件正在執行的一個任務是一個死迴圈,那麼會導致後續其他的任務無法正常執行,所以js在同步機制的缺陷下設計出了非同步模式

在非同步執行的模式下,每一個非同步的任務都有其自己一個或著多個回撥函式,這樣當前在執行的非同步任務執行完之後,不會馬上執行事件佇列中的下一項任務,而是執行它的回撥函式,而下一項任務也不會等當前這個回撥函式執行完,因為它也不能確定當前的回撥合適執行完畢,只要引它被觸發就會執行,舉個例子

關於 js 中的回撥函式 callback

圖片資源還未請求完畢

上圖可以看到,我要購買一個東西,當我點進物品的詳情頁之後,圖片資源還未請求完畢,而此時我就可以點選add to cart, 發起另一個請求,js任務列表中的新增購物車事件就會開始執行,它的執行也不會干擾到圖片資源的請求任務,這也是非同步執行機制的妙處

2.js的單執行緒瀏覽器核心的多執行緒

說到js的單執行緒,順便再瞭解一下關於瀏覽器核心的多執行緒,關於瀏覽器工作原理此處不做講解,因為自己研究的不深入,等待研究學習研究透徹再分享

關於 js 中的回撥函式 callback

瀏覽器常駐三大執行緒: js引擎執行緒,GUI渲染執行緒,瀏覽器事件觸發執行緒

看到此圖你是不是會豁然開朗許多,因為瀏覽器是一個多執行緒的執行環境,在瀏覽器的核心中分配了多個執行緒,最主要的執行緒之一即是js引擎的執行緒,同時js事件佇列中的非同步請求,互動事件觸發,定時器等事件都是由瀏覽器的事件觸發執行緒進行監聽的,瀏覽器的事件觸發執行緒被觸發後會把任務加入到js 引擎的任務佇列中,當js 引擎空閒時候就會開始執行該任務

完結

以上就是本篇文章的全部內容,由對回撥函式的陌生到熟悉和使用,以及對同步/非同步的概念,還有js的執行機制以及瀏覽器核心的多執行緒機制相信大家都有了一個簡單的知識脈絡,希望通過此文提到的內容,每個小夥伴去查閱更深入的資料,於此同時我也會不斷的去修繕,所以我們不能做一個知其然而不知其所以然的程式設計師,要有充分的好奇心去學習它,帶著學習讓我們受益的心態去做和研究自己感興趣的東西是一件非常快樂的事情,希望我可以把我的快樂帶給每一位看文章的小夥伴,也希望你多多給我提出意見,讓我們一起在學習的路上共同發現和成長,2107年歡迎你和我一起做一個不斷努力學習的知識分子

Cayley 一個不斷努力學習的女程式設計師

相關文章