惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
T
The Exploit Database - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
T
Tailwind CSS Blog
V
V2EX
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
IT之家
IT之家
PCI Perspectives
PCI Perspectives
腾讯CDC
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Commits to openclaw:main
Recent Commits to openclaw:main
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
N
News and Events Feed by Topic
博客园 - 三生石上(FineUI控件)
Help Net Security
Help Net Security
雷峰网
雷峰网
有赞技术团队
有赞技术团队
Last Week in AI
Last Week in AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
GbyAI
GbyAI
O
OpenAI News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
S
Security Affairs
F
Fortinet All Blogs
L
LINUX DO - 最新话题
博客园 - 【当耐特】
Webroot Blog
Webroot Blog
Schneier on Security
Schneier on Security
W
WeLiveSecurity
Security Latest
Security Latest
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tenable Blog
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Simon Willison's Weblog
Simon Willison's Weblog
Cyberwarzone
Cyberwarzone
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
C
CERT Recently Published Vulnerability Notes
Engineering at Meta
Engineering at Meta
P
Palo Alto Networks Blog
博客园 - 叶小钗
T
Threatpost
H
Heimdal Security Blog
Microsoft Security Blog
Microsoft Security Blog

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
Everything About Callback Functions in JavaScript
Dmitri Pavlutin · 2020-12-22 · via Dmitri Pavlutin Blog

The callback function is one of those concepts that every JavaScript developer should know. Callbacks are used in arrays, timer functions, promises, event handlers, and much more.

In this post, I will explain the concept of a callback function. Also, I'll help you distinguish the 2 types of callbacks: synchronous and asynchronous.

1. The callback function

How can you compose a message to greet a person?

Let's create a function greet(name) that accepts a name argument. The function should return the greeting message:


function greet(name) {

return `Hello, ${name}!`;

}

greet('Cristina'); // => 'Hello, Cristina!'


What about greeting a list of persons? That's possible using a special array method array.map():


const persons = ['Cristina', 'Ana'];

const messages = persons.map(greet);

messages; // => ['Hello, Cristina!', 'Hello, Ana!']


persons.map(greet) takes each item of the persons array, and invokes the function greet() using each item as an invocation argument: greet('Cristina'), greet('Ana').

What's interesting is that persons.map(greet) method accepts greet() function as an argument. Doing so makes the greet() a callback function.

The persons.map(greet) is a function that accepts another function as an argument, so it is named a higher-order function.

The callback function is supplied as an argument to a higher-order function that invokes ("calls back") the callback function to perform an operation.

What's important is that the higher-order function takes the full responsibility of invoking the callback and supplying it with the right arguments.

In the previous example, the higher-order function persons.map(greet) takes the responsibility to invoke the greet() callback function with each item of the array as an argument: 'Cristina' and 'Ana'.

That brings to an easy rule for identifying callbacks. If you've defined a function and you're not invoking it by yourself — but rather supply as an argument to another function — then you've created a callback.

You can always write by yourself higher-order functions that use callbacks. For example, here's an equivalent version the array.map() method:


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) is a higher-order function since it accepts a callback function as an argument, and then inside of its body invokes that callback function: callback(item).

Note that a regular function (defined using function keyword) or an arrow function (defined using the fat arrow =>) can equally serve as callbacks.

2. The synchronous callback

There are 2 types of callbacks by the way they're invoked: synchronous and asynchronous callbacks.

The synchronous callback is executed during the execution of the higher-order function that uses the callback.

In other words, the synchronous callbacks are blocking: the higher-order function doesn't complete its execution until the callback is done executing.

For example, recall the map() and greet() functions.


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() is a synchronous callback because it's being executed at the same time as the higher-order function map(). You can try the demo.

The synchronous way to invoke the callbacks:

  1. The higher-order function starts execution: 'map() starts'
  • The callback function executes: 'greet() called'
  • Finally, the higher-order function completes its execution: 'map() completed'

2.1 Examples of synchronous callbacks

A lot of methods of native JavaScript types use synchronous callbacks.

The most used ones are the array methods like 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) method of the string type also accepts a callback that is executed synchronously:


// 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. The asynchronous callback

The asynchronous callback is executed after the execution of the higher-order function.

Simply saying, the asynchronous callbacks are non-blocking: the higher-order function completes its execution without waiting for the callback. The higher-order function makes sure to execute the callback later on a certain event.

In the following example, the later() function is executed with a delay of 2 seconds:


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() is an asynchronous callback because setTimeout(later, 2000) starts and completes its execution, but later() is executed after passing 2 seconds. Try the demo.

The asynchronous way to invoke the callbacks:

  1. The higher-order function starts execution: 'setTimeout() starts'
  2. The higher-order function completes its execution: 'setTimeout() completed'
  3. The callback function executes after 2 seconds: 'later() called'

3.1 Examples of asynchronous callbacks

The timer functions invoke the callbacks asynchronously:


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 event listeners also invoke the event handler function (a subtype of callback functions) asynchronously:


const myButton = document.getElementById('myButton');

myButton.addEventListener('click', function handler() {

console.log('Button clicked!');

});

// Logs 'Button clicked!' when the button is clicked


4. Asynchronous callback function vs asynchronous function

The special keyword async placed before the function definition creates an asynchornous function:


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() is asynchronous since it's prefixed with async. The function fetches await fetch('https://api.github.com/users?per_page=5') first 5 users from GitHub. Then extracts from the response object the JSON data: await resp.json().

The asynchronous functions are syntactic sugar on top of promises. When encountering the expression await <promise> (note that calling fetch() returns a promise), the asynchronous function pauses its execution until the promise is resolved.

An asynchronous callback function and an asynchronous function are different terms.

The asynchronous callback function is executed in a non-blocking manner by the higher-order function. But the asynchronous function pauses its execution while waiting for promises (await <promise>) to resolve.

However... you can use an asynchronous function as an asynchronous callback!

Let's make the asynchornous function fetchUserNames() an asynchronous callback called on button click:


const button = document.getElementById('fetchUsersButton');

button.addEventListener('click', fetchUserNames);


Open the demo and click Fetch Users. When the request completes, you'll see a list of users logged to the console.

5. Summary

The callback is a function that's accepted as an argument and executed by another function (the higher-order function).

There are 2 kinds of callback functions: synchronous and asynchronous.

The synchronous callbacks are executed at the same time as the higher-order function that uses the callback. Synchronous callbacks are blocking.

On the other side, the asynchronous callbacks are executed at a later time than the higher-order function. Asynchronous callbacks are non-blocking.

Quiz: does setTimeout(callback, 0) execute the callback synchronously or asynchronously?