Skip to content

Commit aaff588

Browse files
committed
Comply with the new guidelines of writing patterns
1 parent f9edf6d commit aaff588

File tree

3 files changed

+44
-34
lines changed

3 files changed

+44
-34
lines changed

Diff for: foundational/callback/factorial.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function factorial(num, cb) {
1+
function factorial (num, callback) {
22
setTimeout(() => {
33
try {
44
if (typeof num !== "number") {
@@ -10,13 +10,14 @@ function factorial(num, cb) {
1010
}
1111

1212
let result = 1;
13+
1314
for (let i = 1; i <= num; i++) {
1415
result *= i;
1516
}
1617

17-
cb(null, result);
18+
callback(null, result);
1819
} catch (error) {
19-
cb(error);
20+
callback(error);
2021
}
2122
});
2223
}

Diff for: foundational/callback/mapper.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
function map(values, cb) {
1+
function map (values, callback) {
2+
if (!values || !Array.isArray(values) || values.length === 0) {
3+
throw new Error("Invalid values argument");
4+
}
5+
26
const mapped = [];
37

48
for (let i = 0; i < values.length; i++) {
5-
mapped.push(cb(values[i]));
9+
mapped.push(callback(values[i]));
610
}
711

812
return mapped;

Diff for: foundational/callback/readme.md

+34-29
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,46 @@
11
# The Callback Pattern
22

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.
44

5-
## Explanation
5+
## Implementation
66

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.
88

99
### Callback in a synchronous operation
1010

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.
1212

1313
```javascript
14-
function operation(input, callback) {
14+
function operation (input, callback) {
1515
// Execute any business logic
1616
const result = ...
1717

18-
// Call back with the result
19-
callback(result);
18+
callback(result); // Call back with the result
2019
};
2120

22-
operation(input, function callback(result) {
21+
// Execute the operation given a callback
22+
operation(input, (result) => {
2323
console.log(result);
2424
});
2525
```
2626

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.
2828

2929
### Callback in an asynchronous operation
3030

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.
3232

3333
```javascript
34-
function operation(input, callback) {
34+
function operation (input, callback) {
3535
setTimeout(() => {
3636
// Execute any business logic
3737
const result = ...
3838

39-
// Call back with the result
40-
callback(result);
39+
callback(result); // Call back with the result
4140
});
4241
};
4342

44-
operation(input, function callback(result) {
43+
operation(input, (result) => {
4544
console.log(result);
4645
});
4746
```
@@ -53,32 +52,33 @@ operation(input, function callback(result) {
5352
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.
5453

5554
```javascript
56-
function operation(values, callback) {
55+
function operation (values, callback) {
5756
const results = [];
5857

5958
for (let i = 0; i < values.length; i++) {
60-
// Call with the value and return it back
59+
// Execute the callback for each value
6160
const result = callback(values[i]);
6261

63-
results.push(result);
62+
results.push(result); // Collect the next result
6463
}
6564

6665
return results;
6766
}
6867

6968
const values = [1, 2, 3, 4, 5];
7069

71-
const results = operation(values, function callback(value) {
70+
// Execute the operation
71+
const results = operation(values, (value) => {
7272
return value * 2;
7373
});
7474
```
7575

7676
### Error handling in a callback
7777

78-
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.
7979

8080
```javascript
81-
function operation(input, callback) {
81+
function operation (input, callback) {
8282
setTimeout(() => {
8383
try {
8484
// Execute business logic
@@ -91,7 +91,8 @@ function operation(input, callback) {
9191
});
9292
}
9393

94-
operation(input, function callback(error, result) {
94+
// Execute the operation
95+
operation(input, (error, result) => {
9596
// Error must always come first
9697
if (error) {
9798
return console.error(error);
@@ -101,7 +102,7 @@ operation(input, function callback(error, result) {
101102
});
102103
```
103104

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 completes at 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.
105106

106107
## Considerations
107108

@@ -110,13 +111,16 @@ To sum up, a callback called synchronously blocks the current code until the ope
110111
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:
111112

112113
```javascript
113-
function compute(num, callback) {
114+
import { factorial } from "math";
115+
116+
function compute (num, callback) {
114117
if (cache[num]) {
115118
return callback(cache[num]); // Call back synchronously
116119
}
117120

121+
// Calling the asynchronous factorial
118122
factorial(num, (result) => {
119-
cache[num] = result; // Next time call back synchronously
123+
cache[num] = result; // Save calculation into the cache
120124

121125
callback(result); // Call back asynchronously once
122126
});
@@ -125,23 +129,24 @@ function compute(num, callback) {
125129

126130
> We are skipping the error handling here just for simplicity and readability.
127131
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.
129133

130134
```javascript
131-
function compute(num, callback) {
135+
function compute (num, callback) {
132136
if (cache[num]) {
133-
return setTimeout(() => callback(cache[num])); // Call always back asynchronously
137+
// Call always back asynchronously
138+
return setTimeout(() => callback(cache[num]));
134139
}
135140

136141
factorial(num, (result) => {
137-
cache[num] = result;
142+
cache[num] = result; // Save calculation into the cache
138143

139144
callback(result); // Call back asynchronously
140145
});
141146
}
142147
```
143148

144-
## Implementations
149+
## Use Cases
145150

146151
Below you can find various trivial or real-world implementations of this pattern:
147152

0 commit comments

Comments
 (0)