Skip to content

Commit

Permalink
none
Browse files Browse the repository at this point in the history
  • Loading branch information
freddieventura committed May 11, 2024
1 parent d9f56b1 commit e1f1f9a
Showing 1 changed file with 267 additions and 7 deletions.
274 changes: 267 additions & 7 deletions _posts/2024-05-14-js-intermediate-14-recursive-asynchronous-part1.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,278 @@
---
title: Javascript Intermediate 0
title: Javascript Intermediate 14 - Recursive calling for asynchronous effects part 1
tags: javascript, programming, coding, nodejs, syntax
article_header:
type: cover
image:
src: images/js-intermediate-dog-02.png
---

# Title
I am trying to do a clock handle spinning
It will tick in one of the 8 positions according to the clockhandle been 0 degrees 45 Degrees etc.. | / - \

The clock will spin a number of times (noSpins) in those 8 positions , taking from position to position a time in ms (delay)

Initially my function would have been


```
function clockSpin (noSpins , delay) {
const clockTicks = ['|', '/', '-', '\\', '|', '/', '-', '\\'];
let tickNo = 0;
for (i = 0;i < noSpins; i++) {
tickNo = setTimeout( () => {
return tickNo++
}, delay);
let tickReg = tickNo % 7;
console.log(clockTicks[tickReg]);
}
}
clockSpin(20 , 10000);
```

But this executes all the setTimeout() sequentially as soon as i=0 jumps from i=1 , jumps from i=2
each setTimeout() execution is not for the previous setTimeout() to finnish

For this you need to recursively call this function

```
function clockSpin(noSpins, delay) {
const clockTicks = ['|', '/', '-', '\\', '|', '/', '-', '\\'];
let tickNo = 0;
function spin() {
if (tickNo < noSpins) {
setTimeout(() => {
let tickReg = tickNo % 8; // corrected index range
console.clear();
console.log(clockTicks[tickReg]);
tickNo++;
spin(); // Recursive call to start next iteration after delay
}, delay);
}
}
spin(); // Start the first iteration
}
clockSpin(20, 1000); // Adjusted delay for better visualization
```

Basically sustitute the for loop for the async wrapper function lets call it asyncProcess()
It will be called recursively within the higher-order function setTimeout


```
function spin() {
if (tickNo < noSpins) {
}
}
```

Which synthetically can be

```
function myAsyncFunction(delay) {
let maxIterations = 20;
let i = 0;
function asyncProcess() {
if (i < maxIterations ) {
setTimeout( () => {
console.log('Doing some asyncProcess step: ' + i);
asyncProcess(); // Recursive call
}, delay);
}
}
asyncProcess(); // Start the first Iteration
}
myAsyncFunction(1000);
```

Then inside the call of the async function , you need to nest the recursive call to that


## Creating an asynchronous function

Now we are going to complicate a bit more this
Lets do an async function that process some data, and stores some data too
So say this following function will get one letter of the alphabet, and keeps it in a buffer, when the whole function finnishes will output that buffer


Now we need to create an exit condition of the recursion which will process the asyncBuffer


```
function myAsyncFunction(delay, callback) {
let abcArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'];
let maxIterations = 15;
let i = 0;
let asyncBuffer = ''; // ---> CREATING THE ASYNCBUFFER
function asyncProcess() {
if (i < maxIterations) {
setTimeout(() => {
asyncBuffer += abcArray[i];
i++;
asyncProcess();
}, delay);
} else { // ---> EXIT CONDITON
callback(asyncBuffer); // ---> USING THE CALLBACK TO PROCESS THE BUFFER
}
}
asyncProcess(); // Start the first iteration
}
myAsyncFunction(100, function(result) {
console.log(result); // Output the accumulated result when all iterations are completed
});
Seeing its signature would be something like
function myAsyncFunction(delay: number, callback: (result: string) => void): void
```

Seeing its signature would be something like

```
function myAsyncFunction(delay: number, callback: (result: string) => void): void
```

Now we can see the signatures of the higher-order functions , the ones that have callback functions as arguments

In this case this function accept two parameters
- delay: number , One var name called delay , which is of number datatype
- callback: (result: string) => void , Second parameter is a callback function which in turn accepts
- result: string , it returns nothing

This means that the callback function can be something like


```
function(result) {
console.log(result);
}
```

Which will be executed upon exit of recursion
Or simplified


```
myAsyncFunction(100, (result) => console.log(result)); // abcdefghijklmno
```
Note that the name of the parameter is not strict, you can change it an it will work nicely

```
myAsyncFunction(100, (res) => console.log(res)); // abcdefghijklmno
```


## Adding a failureCallback


Lets complicate this function so:
- Upon finnishing reading the alphabetAray (abcArray), it will check for the length of the buffer , asyncBuffer
- If asyncBuffer length is below 15 , then the process has failed somehow.


We will be doing two things, first introducing a fail check when appending the data of the array to the buffer


```
if (abcArray[i]) asyncBuffer += abcArray[i];
```

Then on the Exit condition of the Recursive function, we will do a check, which will call the success callback


```
function myAsyncFunction(delay,successCallback, failureCallback) {
let abcArray = ['a', 'b', 'c', 'd', 'e'];
// let abcArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'];
let maxIterations = 15;
let i = 0;
let asyncBuffer = '';
function asyncProcess() {
if (i < maxIterations) {
setTimeout(() => {
if (abcArray[i]) asyncBuffer += abcArray[i];
i++;
asyncProcess();
}, delay);
} else {
if (asyncBuffer.length >= 15) {
successCallback(asyncBuffer); // Call the successCallback with the accumulated result
} else {
failureCallback('AsyncBuffer length is below 15.'); // Call the failureCallback
}
}
}
asyncProcess(); // Start the first iteration
}
myAsyncFunction(
100,
(res) => console.log('Success:', res),
(err) => console.log('Failure:', err)
);
```

Now you can comment out abcArray and uncomment its different forms and check

Now its signature is


```
function myAsyncFunction(
delay: number,
successCallback: (result: string) => void,
failureCallback: (error: string) => void
): void
```

And will take us to the next chapter

Note that for the previous examples we have used the global object setTimeout(), so we could simulate processes that take a bit of computing time.
Though in the last part of the tutorial we have created a fully pleged asyncProcess().
This setTimeout() function is not needed now , it helped at the bengining to identify the issue, but as long as you keep the basic boiler-plate we can establish it like this


```
function myAsyncFunction(someParam, successCallback, failureCallback) {
let maxIterations = 15;
let i = 0;
let asyncBuffer = '';
function asyncProcess() {
if (i < maxIterations) {
// SOME CODE BLOCK HERE USING someParam
i++;
asyncProcess();
} else {
if (asyncBuffer.length >= 15) {
successCallback(asyncBuffer); // Call the successCallback
} else {
failureCallback('Error message'); // Call the failureCallback
}
}
}
asyncProcess(); // Start the first iteration
}
myAsyncFunction(100, (res) => console.log('Success:', res), (err) => console.log('Failure:', err));
```

Note that the exit conditions on the else, `(i >= maxIterations)` it will call one of the callback functions


## Javascript Intermediate tutorials

Expand All @@ -31,8 +296,3 @@ As main source of information I list the following.
- [Mdn Web Docs Web API](https://developer.mozilla.org/en-US/docs/Web/API)

Which I comfortably read from my terminal via [vim-dan](https://github.com/freddieventura/vim-dan)

## Reference sources

1. []()
2. []()

0 comments on commit e1f1f9a

Please sign in to comment.