JavaScript 中回调函数有哪些
這期內容當中小編將會給大家帶來有關JavaScript 中回調函數有哪些,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
什么是函數?
函數是在其中有一組代碼的邏輯構件,用來執行特定任務。實際上為了易于調試和維護,函數允許以更有組織的方式去編寫代碼。函數還允許代碼重用。
你只需定義一次函數,然后在需要時去調用它,而不必一次又一次地編寫相同的代碼。
聲明一個函數
現在,讓我們看看如何在 javascript 中聲明一個函數。
-
鴻蒙官方戰略合作共建——HarmonyOS技術社區
-
使用函數的構造函數: 在這種方法中,函數是在“函數”的構造函數的幫助下創建的。從技術上講,這種方法比使用函數表達式語法和函數聲明語句語法去聲明函數的方法效率要低。
-
使用函數表達式: 通常這種方法與變量分配相同。簡而言之,函數主體被視為一個表達式,并且該表達式被分配給一個變量。使用這種語法定義的函數可以是命名函數或匿名函數。
沒有名稱的函數被稱為匿名函數。匿名函數是自調用的,這意味著它會自動調用起自身。這種行為也稱為立即調用的函數表達式(IIFE)。
-
鴻蒙官方戰略合作共建——HarmonyOS技術社區
-
使用函數聲明: 這種方法是 JavaScript 中常用的老派方法。在關鍵字“function”之后,你必須指定函數的名稱。之后,如果函數接受多個參數或參數,也需要提及它們。雖然這部分是完全可選的。
在函數體中,函數必須將一個值返回給調用方。遇到 return 語句后,該函數將會停止執行。在函數內部,參數將會充當局部變量。
同樣,在函數內部聲明的變量是該函數的局部變量。局部變量只能在該函數內訪問,因此具有相同名稱的變量可以輕松地用于不同的函數。
調用一個函數
在下列任何一種情況下,將調用之前聲明的函數:
-
發生事件時,例如,用戶單擊按鈕,或者用戶從下拉列表中選擇某些選項等等。
-
從 javascript 代碼中調用該函數時。
-
該函數可以自動調用,我們已經在匿名函數表達式中進行了討論。
() 運算符調用該函數。
什么是回調函數?
按照 MDN 的描述:回調函數是作為參數傳給另一個函數的函數,然后通過在外部函數內部調用該回調函數以完成某種操作。
讓我用人話解釋一下,回調函數是一個函數,將會在另一個函數完成執行后立即執行。回調函數是一個作為參數傳給另一個 JavaScript 函數的函數。這個回調函數會在傳給的函數內部執行。
在 JavaScript 中函數被看作是一類對象。對于一類對象,我們的意思是指數字、函數或變量可以與語言中的其他實體相同。作為一類對象,可以將函數作為變量傳給其他函數,也可以從其他函數中返回這些函數。
可以執行這種操作的函數被稱為高階函數。回調函數實際上是一種模式。 “模式”一詞表示解決軟件開發中常見問題的某種行之有效的方法。最好將回調函數作為回調模式去使用。
為什么我們需要回調
客戶端 JavaScript 在瀏覽器中運行,并且瀏覽器的主進程是單線程事件循環。如果我們嘗試在單線程事件循環中執行長時間運行的操作,則會阻止該過程。從技術上講這是不好的,因為過程在等待操作完成時會停止處理其他事件。
例如,alert 語句被視為瀏覽器中 javascript 中的阻止代碼之一。如果運行 alert,則在關閉 alert 對話框窗口之前,你將無法在瀏覽器中進行任何交互。為了防止阻塞長時間運行的操作,我們使用了回調。
讓我們深入研究一下,以便使你準確了解在哪種情況下使用回調。
在上面的代碼片段中,首先執行 getMessage()函數,然后執行 displayMessage() 。兩者都在瀏覽器的控制臺窗口中顯示了一條消息,并且都立即執行。
在某些情況下,一些代碼不會立即執行。例如,如果我們假設 getMessage() 函數執行 API 調用,則必須將請求發送到服務器并等待響應。這時我們應該如何處理呢?
如何使用回調函數
我認為與其告訴你 JavaScript 回調函數的語法,不如在前面的例子中實現回調函數更好。修改后的代碼段顯示在下面的截圖中。
為了使用回調函數,我們需要執行某種無法立即顯示結果的任務。為了模擬這種行為,我們用 JavaScript 的 setTimeout()函數。該函數會暫停兩秒鐘,然后在控制臺窗口中顯示消息“ Hi,there”。
“顯示的消息”將被顯示在瀏覽器的控制臺窗口中。在這種情況下,首先,我們需要等待 getMessage() 函數。成功執行此函數后,再執行 displayMessage() 函數。
回調的工作方式
讓我解釋一下前面的例子在幕后發生的事。
從上一個例子可以看到,在 getMessage() 函數中,我們傳遞了兩個參數。第一個參數是 msg 變量,該變量顯示在瀏覽器的控制臺窗口中,第二個參數是回調函數。
現在,你可能想知道為什么將回調函數作為參數進行傳遞 —— 要實現回調函數,我們必須將一個函數作為參數傳給另一個函數。
在 getMessage() 完成任務后,我們將調用回調函數。之后,當調用 getMessage() 函數時,將引用傳給displayMessage() 函數,該函數就是回調函數。
注意,當調用 getMessage() 函數時,我們僅將其引用傳給 displayMessage() 函數。這就是為什么你不會在它旁邊看到函數調用運算符,也就是() 符號。
Javascript 回調是異步的嗎?
JavaScript 被認為是單線程腳本語言。單線程是指 JavaScript 一次執行一個代碼塊。當 JavaScript 忙于執行一個塊時,它不可能移到下一個塊。
換句話說,我們可以認為 JavaScript 代碼本質上總是阻塞的。但是這種阻塞性使我們無法在某些情況下編寫代碼,因為在這些情況下我們沒有辦法在執行某些特定任務后立即得到結果。
我談論的任務包括以下情況:
-
通過對某些端點進行 API 調用來獲取數據。
-
通過發送網絡請求從遠程服務器獲取一些資源(例如,文本文件、圖像文件、二進制文件等)。
為了處理這些情況,必須編寫異步代碼,而回調函數是處理這些情況的一種方法。所以從本質上上說,回調函數是異步的。
Javascript 回調地獄
當多個異步函數一個接一個地執行時,會產生回調地獄。它也被稱為厄運金字塔。
假設你要獲取所有 Github 用戶的列表。然后在用戶中搜索 JavaScript 庫的主要貢獻者。再然后,你想要在用戶中獲取姓名為 John 的人員的詳細信息。
為了在回調的幫助下實現這個功能,代碼應該如下所示:
http.get('https://api.github.com/users',function(users){/*Displayallusers*/console.log(users);http.get('https://api.github.com/repos/javascript/contributors?q=contributions&order=desc',function(contributors){/*Displayalltopcontributors*/console.log(contributors);http.get('https://api.github.com/users/Jhon',function(userData){/*Displayuserwithusername'Jhon'*/console.log(userData);});});});
從上面的代碼片段中,你可以看到代碼變得更加難以理解,以及難以維護和修改。這是由回調函數的嵌套而引發的。
如何避免回調地獄?
可以使用多種技術來避免回調地獄,如下所示。
-
鴻蒙官方戰略合作共建——HarmonyOS技術社區
-
使用promise
-
借助 async-await
-
使用 async.js 庫
使用 Async.js 庫
讓我們談談怎樣用 async.js 庫避免回調地獄。
根據 async.js 官方網站的描述:Async 是一個工具模塊,它提供了直接、強大的函數來使用異步 JavaScript。
Async.js 總共提供約 70 個函數。現在,我們將僅討論其中兩個,即 async.waterfall() 和 async.series()。
async.waterfall()
當你要一個接一個地運行某些任務,然后將結果從上一個任務傳到下一個任務時,這個函數非常有用。它需要一個函數“任務”數組和一個最終的“回調”函數,它會在“任務”數組中所有的函數完成后,或者用錯誤對象調用“回調”之后被調用。
varasync=require('async');async.waterfall([function(callback){/*Here,thefirstargumentvalueisnull,itindicatesthatthenextfunctionwillbeexecutedfromthearrayoffunctions.Ifthevaluewastrueoranystringthenfinalcallbackfunctionwillbeexecuted,otherremainingfunctionsinthearraywillnotbeexecuted.*/callback(null,'one','two');},function(param1,param2,callback){//param1nowequals'one'andparam2nowequals'two'callback(null,'three');},function(param1,callback){//param1nowequals'three'callback(null,'done');}],function(err,result){/*Thisisthefinalcallbackfunction.resultnowequals'done'*/});
async.series()
當你要運行一個函數然后在所有函數成功執行后需要獲取結果時,它很有用。 async.waterfall() 和 async.series() 之間的主要區別在于, async.series() 不會將數據從一個函數傳遞到另一個函數。
async.series([function(callback){//dosomestuff...callback(null,'one');},function(callback){//dosomemorestuff...callback(null,'two');}],//optionalcallbackfunction(err,results){//resultsisnowequalto['one','two']});
Javascript 回調與閉包
閉包
用技術術語來說,閉包是捆綁在一起的函數的組合,引用了其周圍的狀態。
簡而言之,閉包允許從內部函數訪問外部函數的作用域。
要使用閉包,我們需要在一個函數內部定義另一個函數。然后,我們需要將其返回或傳給另一個函數。
回調
從概念上講,回調類似于閉包。回調基本上是把一個函數作為另一個函數的用法。
總結
以上是生活随笔為你收集整理的JavaScript 中回调函数有哪些的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Java编写模仿的太阳系(九星行旋转)
- 下一篇: 《C语言深度解剖》学习笔记之符号