You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: foundational/callback/readme.md
+34-29
Original file line number
Diff line number
Diff line change
@@ -1,47 +1,46 @@
1
1
# The Callback Pattern
2
2
3
-
A callback is nothing more than a function, which in JavaScript is considered a **first-class** object. Functions can be assigned to variables, passed as arguments in other functions and even returned by functions. In both the synchronous and asynchronous world of JavaScript this is considered a foundational concept, because either we can pass functionality to be executed at the same cycle of the event loop or at a future event loop cycle without blocking the current code.
3
+
A callback is nothing more than a function, which in JavaScript is considered a **first-class** object. Functions can be assigned to variables, passed as arguments in other functions and even returned by functions. In both the synchronous and asynchronous world of JavaScript this is considered a foundational concept, because either we can pass functionality to be executed at the current cycle (sync) or at a subsequent cycle (async) of the event loop.
4
4
5
-
## Explanation
5
+
## Implementation
6
6
7
-
As callback is just a function, it can be passed to another function and invoked with the result when the operation in that function completes. It doesn't need to be an asynchronous operation though, callbacks can be used both in synchronous and asynchronous operations.
7
+
As callback is just a function, it can be passed to another function and invoked with the result when the operation in that function completes. It doesn't need to be an asynchronous operation though, callbacks can be used both in **synchronous** and **asynchronous** operations.
8
8
9
9
### Callback in a synchronous operation
10
10
11
-
In a synchronous operation, the callback patterns should be implemented like so,
11
+
In a synchronous operation, the callback pattern should be implemented like so.
12
12
13
13
```javascript
14
-
functionoperation(input, callback) {
14
+
functionoperation(input, callback) {
15
15
// Execute any business logic
16
16
constresult=...
17
17
18
-
// Call back with the result
19
-
callback(result);
18
+
callback(result); // Call back with the result
20
19
};
21
20
22
-
operation(input, functioncallback(result) {
21
+
// Execute the operation given a callback
22
+
operation(input, (result) => {
23
23
console.log(result);
24
24
});
25
25
```
26
26
27
-
where input can be any valid value or either a list of separated input values followed be the callback which always should come last.
27
+
where input can be any valid value or either a list of separated input values followed be the `callback` which always should come last.
28
28
29
29
### Callback in an asynchronous operation
30
30
31
-
In an asynchronous operation though, a callback should always be called asynchronously in order to be invoked in the next event loop cycles.
31
+
In an asynchronous operation though, a `callback` should always be called asynchronously in order to be invoked in the next event loop cycles.
32
32
33
33
```javascript
34
-
functionoperation(input, callback) {
34
+
functionoperation(input, callback) {
35
35
setTimeout(() => {
36
36
// Execute any business logic
37
37
constresult=...
38
38
39
-
// Call back with the result
40
-
callback(result);
39
+
callback(result); // Call back with the result
41
40
});
42
41
};
43
42
44
-
operation(input, functioncallback(result) {
43
+
operation(input, (result)=> {
45
44
console.log(result);
46
45
});
47
46
```
@@ -53,32 +52,33 @@ operation(input, function callback(result) {
53
52
The callback pattern can be used in other use cases as well, for instance in cases where you need to transform the values of a collection. In such cases a callback is given a value and returns it back modified instead of just handle it.
Another important thing is to be consistent with error handling in callbacks and have any error come first when propagating errors back.
78
+
Another important thing is to be consistent with error handling in callbacks, in case an `error` is thrown the `callback` has always to be called given that error as the first and only argument.
79
79
80
80
```javascript
81
-
functionoperation(input, callback) {
81
+
functionoperation(input, callback) {
82
82
setTimeout(() => {
83
83
try {
84
84
// Execute business logic
@@ -91,7 +91,8 @@ function operation(input, callback) {
@@ -101,7 +102,7 @@ operation(input, function callback(error, result) {
101
102
});
102
103
```
103
104
104
-
To sum up, a callback called synchronously blocks the current code until the operation completes, where an asynchronously called callback returns control back immediately and completes, given the result, at a later event loop cycle. In any use case mentioned above, there is no syntactic difference which means that the intent of the callback should always be explained in the documentation of the API about the synchronous or asynchronous manner the callback is called.
105
+
To sum up, a callback called synchronously blocks the current code until the operation completes, where an asynchronously called callback returns control back immediately and completesat a subsequent event loop cycle. As mentioned above, there is no syntactic difference which means that the intent of the callback should always be explained in the documentation of the API about the synchronous or asynchronous manner the callback is called.
105
106
106
107
## Considerations
107
108
@@ -110,13 +111,16 @@ To sum up, a callback called synchronously blocks the current code until the ope
110
111
Try to avoid inconsistencies in the behavior of a function which is using a callback, either the callback should always be called synchronously or asynchronously. It is considered very bad practice to have a function behave unpredictably mixing synchronous and asynchronous calls to the given callback. Let's say we have a `cache` map object and an asynchronous `factorial` function:
111
112
112
113
```javascript
113
-
functioncompute(num, callback) {
114
+
import { factorial } from"math";
115
+
116
+
functioncompute (num, callback) {
114
117
if (cache[num]) {
115
118
returncallback(cache[num]); // Call back synchronously
116
119
}
117
120
121
+
// Calling the asynchronous factorial
118
122
factorial(num, (result) => {
119
-
cache[num] = result; //Next time call back synchronously
123
+
cache[num] = result; //Save calculation into the cache
120
124
121
125
callback(result); // Call back asynchronously once
122
126
});
@@ -125,23 +129,24 @@ function compute(num, callback) {
125
129
126
130
> We are skipping the error handling here just for simplicity and readability.
127
131
128
-
Once you first compute the factorial of a number the next time you request the same number's factorial, the call to the callback will be synchronous. Instead try to stick with either synchronous or asynchronous behavior in any function expecting a callback.
132
+
Once you first compute the `factorial` of a number the next time you request the same number's factorial, the call to the callback will be synchronous. Instead try to stick with either synchronous or asynchronous behavior in any function expecting a callback.
129
133
130
134
```javascript
131
-
functioncompute(num, callback) {
135
+
functioncompute(num, callback) {
132
136
if (cache[num]) {
133
-
returnsetTimeout(() =>callback(cache[num])); // Call always back asynchronously
137
+
// Call always back asynchronously
138
+
returnsetTimeout(() =>callback(cache[num]));
134
139
}
135
140
136
141
factorial(num, (result) => {
137
-
cache[num] = result;
142
+
cache[num] = result;// Save calculation into the cache
138
143
139
144
callback(result); // Call back asynchronously
140
145
});
141
146
}
142
147
```
143
148
144
-
## Implementations
149
+
## Use Cases
145
150
146
151
Below you can find various trivial or real-world implementations of this pattern:
0 commit comments