JavaScript回撥函式的高手指南
回撥函式是每個前端程式設計師都應該知道的概念之一。回撥可用於陣列、計時器函式、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() 是同步回撥。
同步回撥的步驟:
1. 高階函式開始執行:'map() starts'
2. 回撥函式執行:'greet() called'
3. 最後高階函式完成它自己的執行過程:'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 arraysconst 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 stringsconst 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 秒後執行。
非同步呼叫回撥的步驟:
1. 高階函式開始執行:'setTimeout()starts'
2. 高階函式完成其執行: 'setTimeout() completed'
3. 回撥函式在 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
const users = await resp.json();
const names = users.map( ({ login }) => login);
console .log(names);
}
fetchUserNames() 是非同步的,因為它以 async 為字首。函式 await fetch 從 GitHub 上獲取前5個使用者 。然後從響應物件中提取 JSON 資料:await resp.json()。
非同步函式是 promise 之上的語法糖。當遇到表示式 await <promise> (呼叫 fetch() 會返回一個promise)時,非同步函式會暫停執行,直到 promise 被解決。
非同步回撥函式和非同步函式是不同的兩個術語。
非同步回撥函式由高階函式以非阻塞方式執行。但是非同步函式在等待 promise(await <promise>)解析時會暫停執行。
但是你可以把非同步函式用作非同步回撥!
讓我們把非同步函式 fetch UserNames() 設為非同步回撥,只需單擊按鈕即可呼叫:
const button = document .getElementById( 'fetchUsersButton' );
button.addEventListener( 'click' , fetchUserNames);
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69989477/viewspace-2754808/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaScript 回撥函式JavaScript函式
- JavaScript回撥函式JavaScript函式
- 更智慧的JavaScript回撥函式解析JavaScript函式
- 深入理解 JavaScript 回撥函式JavaScript函式
- JavaScript:鉤子函式與回撥函式的區別JavaScript函式
- 理解javascript中的回撥函式(callback)【轉】JavaScript函式
- 回撥函式函式
- JavaScript回撥函式應用淺析JavaScript函式
- 回撥函式的作用函式
- JS—回撥函式JS函式
- 動畫回撥函式動畫函式
- java回撥函式Java函式
- 回撥函式(CallBack)函式
- [JS]回撥函式和回撥地獄JS函式
- 回撥函式,求積函式函式
- 回撥函式的理解(一)函式
- js中的回撥函式JS函式
- Java回撥函式的理解Java函式
- 回撥函式 與 函式閉包函式
- 函式指標&回撥函式Callback函式指標
- TLS回撥函式(Note)TLS函式
- java 回撥函式示例Java函式
- Python回撥函式Python函式
- android回撥函式Android函式
- 函式回撥(C++)函式C++
- JavaScript 非同步操作裡的巢狀回撥函式JavaScript非同步巢狀函式
- js 中的submit 回撥函式JSMIT函式
- python中的回撥函式Python函式
- C++中的回撥函式C++函式
- JavaScript中回撥函式知識點,都在這了!JavaScript函式
- JS閉包函式和回撥函式JS函式
- C++回撥函式 用法C++函式
- Python/OpenCV:回撥函式PythonOpenCV函式
- java回撥函式機制Java函式
- JS之回撥函式(callback)JS函式
- js函式回撥錯誤JS函式
- c++回撥函式(下)C++函式
- C++回撥函式示例C++函式