回呼函數是每個前端程式設計師都應該知道的概念之一。回調可用於陣列、計時器函數、promise、事件處理。本文將會解釋回呼函數的概念,同時幫你區分兩種回呼:同步和非同步。
1、回呼函數
#先寫一個向人打招呼的函數。
只需要建立一個接受 name
參數的函數 greet(name)
。這個函數要回傳打招呼的訊息:
function greet(name) { return `Hello, ${name}!`; } greet('Cristina'); // => 'Hello, Cristina!'
如果向很多人打招呼該怎麼辦?可以用特殊的陣列方法 array.map()
可以實作:
const persons = ['Cristina', 'Ana']; const messages = persons.map(greet); messages; // => ['Hello, Cristina!', 'Hello, Ana!']
persons.map(greet)
可以取得persons
陣列的所有元素,並分別以每個元素作為呼叫參數來呼叫greet()
函數:`greet('Cristina')
, greet('Ana')
。
有趣的是 persons.map(greet)
方法可以接受 greet()
函數作為參數。這樣 greet()
就變成了回呼函數。
persons.map(greet)
是用另一個函數作為參數的函數,因此稱為高階函數。
回呼函數作為高階函數的參數,高階函數透過呼叫回呼函數來執行操作。
重要的是高階函數負責呼叫回調,並為其提供正確的參數。
前面的範例中,高階函數persons.map(greet)
負責呼叫 greet()
函數,並且分別將陣列中所有的元素'Cristina'
和Ana '
作為參數。
這就為識別回呼提供了一條簡單的規則。如果你定義了一個函數,並將其作參數提供給另一個函數的話,那麼這就創建了一個回呼。
你可以自己寫一個使用回呼的高階函數。以下是array.map()
方法的等效版本:
function map(array, callback) { const mappedArray = []; for (const item of array) { mappedArray.push( callback(item) ); } return mappedArray; } function greet(name) { return `Hello, ${name}!`; } const persons = ['Cristina', 'Ana']; const messages = map(persons, greet);messages; // => ['Hello, Cristina!', 'Hello, Ana!']
map(array, callback)
是高階函數,因為它用回呼函數作為參數,然後在其主體內部呼叫該回呼函數:callback(item)
。
注意,常規函數(以關鍵字 function
定義)或箭頭函數(以粗箭頭 =>
定義)同樣可以作為回調使用。
2、同步回呼
回呼的呼叫方式有兩種:同步和非同步回呼。
同步回呼是「阻塞」的:高階函數直到回呼函數完成後才繼續執行。
例如,呼叫 map()
和 greet()
函數。
function map(array, callback) { console.log('map() starts'); const mappedArray = []; for (const item of array) { mappedArray.push(callback(item)) } console.log('map() completed'); return mappedArray; } function greet(name) { console.log('greet() called'); return `Hello, ${name}!`; } const persons = ['Cristina']; map(persons, greet); // logs 'map() starts' // logs 'greet() called' // logs 'map() completed'
其中 greet()
是同步回呼。
同步回呼的步驟:
高階函數開始執行:
'map() starts'
- ##回呼函數執行:
'greet() called'
- #.最後高階函數完成它自己的執行過程:
'map() completed'
同步回呼的範例
許多原生JavaScript 類型的方法都會使用同步回呼。 最常用的是array 的方法,例如:array.map(callback),
array.forEach(callback),
array.find(callback ),
array.filter(callback),
array.reduce(callback, init)
// Examples of synchronous callbacks on arrays const persons = ['Ana', 'Elena']; persons.forEach( function callback(name) { console.log(name); } ); // logs 'Ana' // logs 'Elena' const nameStartingA = persons.find( function callback(name) { return name[0].toLowerCase() === 'a'; } ); nameStartingA; // => 'Ana' const countStartingA = persons.reduce( function callback(count, name) { const startsA = name[0].toLowerCase() === 'a'; return startsA ? count + 1 : count; }, 0 ); countStartingA; // => 1字串類型的
string.replace( callback) 方法也能接受同步執行的回呼:
// Examples of synchronous callbacks on strings const person = 'Cristina'; // Replace 'i' with '1' person.replace(/./g, function(char) { return char.toLowerCase() === 'i' ? '1' : char; } ); // => 'Cr1st1na'
#3、非同步回呼
非同步回呼是「非阻塞的」:高階函數無需等待回調完成即可完成其執行。高階函數可確保稍後在特定事件上執行回呼。 在以下的例子中,later() 函數的執行延遲了2 秒:
console.log('setTimeout() starts'); setTimeout(function later() { console.log('later() called'); }, 2000); console.log('setTimeout() completed'); // logs 'setTimeout() starts' // logs 'setTimeout() completed' // logs 'later() called' (after 2 seconds)
later() 是一個非同步回調,因為
setTimeout(later,2000) 啟動並完成了執行,但是
later() 在2 秒後執行。
- 高階函數開始執行:
'setTimeout()starts'
- 高階函數完成其執行:
'setTimeout() completed'
- # 回呼函數在2 秒後執行:
'later( ) called'
異步回呼的範例
計時器函數非同步呼叫回呼:setTimeout(function later() { console.log('2 seconds have passed!'); }, 2000); // After 2 seconds logs '2 seconds have passed!' setInterval(function repeat() { console.log('Every 2 seconds'); }, 2000); // Each 2 seconds logs 'Every 2 seconds!'#DOM 事件偵聽器也非同步呼叫事件處理函數(回呼函數的子類型):
const myButton = document.getElementById('myButton'); myButton.addEventListener('click', function handler() { console.log('Button clicked!'); }); // Logs 'Button clicked!' when the button is clicked
#4、非同步回呼函數與非同步函數
在函數定義之前加上特殊關鍵字async 會建立一個非同步函數:
async function fetchUserNames() { const resp = await fetch('https://api.github.com/users?per_page=5'); const users = await resp.json(); const names = users.map(({ login }) => login); console.log(names); }
fetchUserNames()
是异步的,因为它以 async
为前缀。函数 await fetch('https://api.github.com/users?per_page=5')
从 GitHub 上获取前5个用户 。然后从响应对象中提取 JSON 数据:await resp.json()
。
异步函数是 promise 之上的语法糖。当遇到表达式 await <promise></promise>
(调用 fetch()
会返回一个promise)时,异步函数会暂停执行,直到 promise 被解决。
异步回调函数和异步函数是不同的两个术语。
异步回调函数由高阶函数以非阻塞方式执行。但是异步函数在等待 promise(await <promise></promise>
)解析时会暂停执行。
但是你可以把异步函数用作异步回调!
让我们把异步函数 fetch UserNames()
设为异步回调,只需单击按钮即可调用:
const button = document.getElementById('fetchUsersButton'); button.addEventListener('click', fetchUserNames);
总结
回调是一个可以作为参数传给另一个函数(高阶函数)执行的函数。
回调函数有两种:同步和异步。
同步回调是阻塞的。
异步回调是非阻塞的。
【相关推荐:javascript学习教程】
以上是深入解析JavaScript中的回呼函數(同步與非同步)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

如何在Quartz中提前發送任務通知在使用Quartz定時器進行任務調度時,任務的執行時間是由cron表達式設定的。現�...

在JavaScript中如何獲取原型鏈上函數的參數在JavaScript編程中,理解和操作原型鏈上的函數參數是常見且重要的任�...

在微信小程序web-view中使用Vue.js動態style位移失效的原因分析在使用Vue.js...


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

禪工作室 13.0.1
強大的PHP整合開發環境

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境