I come from PIC assembly-language programming where programs normally run continuously. I've now been learning Javascript for quite a while but have become a little blocked with the use of callback functions when they are given as a parameter of a call to an async function. I do realize that callbacks have been explained 'forever', but I have read about 10 books now cover to cover and get no clear answer.
First of all, most descriptions "brush under the carpet" how async functions are actually implemented in code. I see now that this is not normally part of Javascript but a part of the underlying host code (the browser - or even, perhaps, the OS that the browser runs on). But Javascript must then have a mechanism to run functions that are not themselves part of Javascript language and the underlying host must have a mechanism for allowing Javascript to continue. I have never seen any code for this. I wonder how exactly does the host code put a specific block of Javascript in an event queue? This is all kept rather quiet it seems.
When it comes to the use of callbacks, I had the following assumption (by analogy), that turns out to be false. I'm cooking and I need some salt, but I don't have any. I send out a friend to buy some salt, but I don't want to stop cooking. So my async function is goBuySomeSalt(nameOfShop, putItOnTable). I continue to cook and expect the salt to arrive later (and then to be putOnTable()). When the salt arrives I will use it in my cooking.
It seems though that Javascript does not allow this. Explanations of callbacks almost universally say that the callback will be called when the async function has finished. So I want to use my salt when my friend gets back. But I can't because I'm still cooking. There seems to be no way to use the salt until I've finished cooking because my friend is waiting right at the back of the event queue and they will only put the salt on the table when I've finished what I'm doing. Thus my request for salt was essentially useless.
Am I missing something? Can I "poll" during my cooking for the salt? Can I be informed when the salt has arrived? (Please note; I've already read about promises etc.)
Below is my code to illustrate this:
function a(){
setTimeout(d, 1000);
console.log ("Please fetch some salt!")
}
function d(){ console.log("Here's your salt - sorry I'm too late");}
a();
for (let i = 0; i < 4000000000; i++) {
if (i%1000000000 == 0) { console.log ("Cooking");}
}
console.log ("finished cooking - but used no salt!!")
The order of the output is:
"Please fetch some salt!" "Cooking" "Cooking" "Cooking" "Cooking" "finished cooking - but used no salt!!" "Here's your salt - sorry I'm too late"
Since its single threaded, you can't do a traditional poll as you would in a multi-threaded environment without using a Web Worker
create a web worker as a blob or separate file:
console.log("Please fetch me some salt");
function d() {
console.log("Here's your salt - sorry I'm too late");
}
// Worker script as a string
const workerScript = `
self.onmessage = function(event) {
if (event.data === 'start') {
c();
}
};
function c() {
for (let i = 0; i < 40000000000; i++) {
if (i % 500000000 === 0) {
postMessage("Cooking");
}
}
postMessage("Finished cooking - but used no salt!!");
}`;
// Create a blob from the worker script
const blob = new Blob([workerScript], { type: 'application/javascript' });
// Create a URL for the blob
const workerUrl = URL.createObjectURL(blob);
// Create a new Worker using the Blob URL
const worker = new Worker(workerUrl);
// Send a message to start the worker process
worker.postMessage('start');
// Listen for messages from the worker
worker.onmessage = function(event) {
console.log(event.data);
};
// Set timeout to simulate delayed function call
setTimeout(d, 400);