Asynchronous execution and onsuccess event handler [duplicate] - javascript

This question already has answers here:
Hidden threads in Javascript/Node that never execute user code: is it possible, and if so could it lead to an arcane possibility for a race condition?
(3 answers)
Closed 7 years ago.
In many js examples, I see calls to functions doing tasks asynchronous, for example:
var objectStoreTitleRequest = objectStore.get(title);
objectStoreTitleRequest.onsuccess = function() {
// Grab the data object returned as the result
var data = objectStoreTitleRequest.result;
}
(This example is based on https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest/onsuccess)
I wonder how this could work if the async execution finished before the onsuccess handler is set. I expected that event handlers added before execution of the async function, but all js examples add handlers after the call (in this case: get()). How is this internally solved? And how can I implement a custom object which provides a similar API? I think this must be something like
{self.result = do_work(); wait for onsuccess handler is set...; if handler_avail -> self.onsuccess(); }

Because Javascript is strictly single-threaded, asynchronous operations can only run their callbacks once other code has finished running.
Therefore, it is impossible for the request to finish between two lines.

This is exactly the reason why you should never call a callback function / event handler synchronously.
For example, the following code is wrong:
function async(val, cb) {
if(val < 0) {
cb();
}
else {
setTimeout(cb, val);
}
}
And must instead be implemented similar to:
function async(val, cb) {
if(val < 0) {
setTimeout(cb, 0);
}
else {
setTimeout(cb, val);
}
}

Related

How can you use a callback to guarantee sequential execution?

I am trying to wrap my head around callbacks and I do not understand how callbacks guarantee that a statement will execute after(in terms of time) another statement which takes an unknown amount of time. I do not care about promises,await,async, etc but just plain callbacks as I am trying to learn.
For example below, my method will execute the callback before the unknown time event has occured. I can see how callbacks can be used to execute something because an event occurred but not how they can be used to guarantee that something will be executed after(in terms of time) something else has finished executing and returned something meaningful.
function foo(callback) {
setTimeout(() => console.log("Do something with unknown time"),
2000);
callback();
}
function callback() {
console.log("Execute callback");
}
foo(callback);
So what I am asking is can callbacks be used to guarantee execution sequence in the time domain ? Or is their only purpose responding to events ?
Callbacks is a way of invoking a function that is passed as a parameter to invoker function(in your example foo). Callbacks guarantee that a function will be invoked if no error occurs before it's call inside the function. Callbacks aren't asynchronous either but the way it executes later inside the function after some line of code makes everyone think it as asynchonous at first.
And as you've added setTimeout function on the above example, setTimeout is an asynchronous callback envoker function that calls it's callback(in your code () => console.log("Do something with unknown time")) asynchronously after a certain defined time(2000). So, setTimeout wont stop the execution for 2 seconds as you've expected, instead it let's the further line of codes execute without worrying about what will happen inside it's callback. So, the callback() will trigger at that instant when foo(callback); is triggered.
You can find more info about callback in here.
You have asked two questions,
Is callback execution sequence guaranteed?
Is callback only respond to events ?
Answer
Yes.
From my understanding, callback is just calling another function to be run now (when it is called)
It is guarantee to run immediately when you call it.
To ensure something is called before the callback is triggered, simply put the things you want to call execute first before callback is conducted.
e.g. from your code, by modify it a bit, callback is guarantee to run after the console.log is executed.
function foo(callback) {
setTimeout(() => {
console.log("Do something with unknown time");
callback();
}, 2000);
}
function callback() {
console.log("Execute callback");
}
foo(callback);
It is the setTimeout which defers the execution, and is not related to callback methodology.
Sure, callback can be used as a callback to respond to event, just like elem.addEventListener("click", callback);. But not only that.
A simple example will be illustrated below.
e.g.
var map = function(arr, callback) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
result.push(callback(arr[i]));
}
return result;
};
map([0, 1, 2, 3], function(item) {
return item * 2;
})
Edited
This edit is referring to
For example, if I am making a database call, I do not know how much time it is going to take for the data to be retrieved. If i try to access it before it has arrived, I'll get an error.
Calling a database, is by no means different from an async http request. So here, I will use XMLHttpRequest to demonstrate how to use callback to ensure this. But normally, these are features provided in browser or node.js already. So you do not need to write it by your own. Of course, to prevent callback hell, I will personally prefer use of Promise or async/await. But this is a bit out of topic.
So let see how XMLHttpRequest can use callback to handle async task.
var sendRequest = function(callback) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this);
}
};
xhttp.open("GET", "filename", true);
xhttp.send();
}
and you can use callback to handle async event. Sometime you dont know when it will happen. And the basic idea how it works is from the example I have said in answer 1.
If I understand you mean correctly, you can use callback as an event to do something, such as: onerror, oncomplete...
In this example, we start to run todo function, and we have oncomplete function which can be used as callback to do something after completing works on todo function.
While running, if there is some error, it will be logged to onerror function.
function todo(oncomplete, onerror) {
try {
console.log("Start...");
console.log("Do something with unknown time");
setTimeout(() => oncomplete(),2000);
// you can try to throw error here to test
// throw new Error("Some error message...");
} catch (e) {
onerror(e);
}
}
function oncomplete() {
console.log("Done!");
}
function onerror(e) {
console.error(e.message);
}
todo(oncomplete, onerror);

Node.js: async callback vs sync callback vs process.nextTick vs setTimeout [duplicate]

This question already has answers here:
I know that callback function runs asynchronously, but why?
(3 answers)
Closed 6 years ago.
I started to develop in node.js just a while ago. Lately, I did some deep dive into the 'event loop' and async mechanism of node. But still I'm not fully understand the different between sync and async callbacks.
In this example from node.js API, I understand why is not clear which function will be called first.
maybeSync(true, () => {
foo();
});
bar();
But, what if we had:
syncOrAsync(arg, () => {
if (arg) {
cb(arg);
return;
}
});
syncOrAsync(true, function(result) {
console.log('result');
});
console.log('after result);
It's not clear to me why they are always execute in sync order, although I did a callback function which should execute by the event loop after the stack is empty ( console.log('after result') was finished ). Do I always need to add process.nextTick(cb); to get async? And what is the diffrent between process.nextTick and setTimeout();?
Unless you have something that is actually async, like timers or external calls etc. the code will always be synchronous, as that's the default state of all javascript code.
Adding a callback doesn't make it asynchronous
Here's an example of asynchronous code
function syncOrAsync(sync, cb) {
if (sync) {
return cb();
} else {
setTimeout(cb, 100); // async, waits 0.1 seconds to call callback
}
}
syncOrAsync(true, function(result) { // synchronous call
console.log('result 1'); // happens first
});
syncOrAsync(false, function(result) { // asynchronous call
console.log('result 2'); // happens last, as it's async
});
console.log('result 3'); // happens second
Using process.nextTick() doesn't really make the functions asynchronous, but it does do somewhat the same
function syncOrAsync() {
console.log('result 1'); // this happens last
}
process.nextTick(syncOrAsync);
console.log('result 2'); // this happens first
This would defer the execution of syncOrAsync until the next pass around the event loop, so it would be in many ways the same as setTimeout(syncOrAsync), but the function still wouldn't be asynchronous, the callback would execute immediately, we've just delay the entire execution of the function.

WinJS, return a promise from a function which may or may not be async

I have a situation where my WinJS app wants to call a function which may or may not be async (e.g. in one situation I need to load some data from a file (async) but at other times I can load from a cache syncronously).
Having a look through the docs I though I could wrap the conditional logic in a promise like:
A)
return new WinJS.Promise(function() { // mystuff });
or possibly use 'as' like this:
B)
return WinJS.Promise.as(function() { // mystuff });
The problem is that when I call this function, which I'm doing from the ready() function of my first page like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function () {
Data.Survey.init().done(function (result) {
// do some stuff with 'result'
});
}
});
When it is written like 'A' it never hits my done() call.
Or if I call it when it's written like 'B', it executes the code inside my done() instantly, before the promise is resolved. It also looks from the value of result, that it has just been set to the content of my init() function, rather than being wrapped up in a promise.
It feels like I'm doing something quite basically wrong here, but I'm unsure where to start looking.
If it's any help, this is a slimmed down version of my init() function:
function init() {
return new WinJS.Promise(function() {
if (app.context.isFirstRun) {
app.surveyController.initialiseSurveysAsync().then(function (result) {
return new WinJS.Binding.List(result.surveys);
});
} else {
var data = app.surveyController.getSurveys();
return new WinJS.Binding.List(data);
}
});
}
Does anyone have any thoughts on this one? I don't believe the 'may or may not be async' is the issue here, I believe the promise setup isn't doing what I'd expect. Can anyone see anything obviously wrong here? Any feedback greatly appreciated.
Generally speaking, if you're doing file I/O in your full init routine, those APIs return promises themselves, in which case you want to return one of those promises or a promise from one of the .then methods.
WinJS.Promise.as, on the other hand, is meant to wrap a value in a promise. But let me explain more fully.
First, read the documentation for the WinJS.Promise constructor carefully. Like many others, you're mistakenly assuming that you just wrap a piece of code in the promise and voila! it is async. This is not the case. The function that you pass to the constructor is an initializer that receives three arguments: a completeDispatcher function, an errorDispatcher function, and a progressDispatcher function, as I like to call them.
For the promise to ever complete with success, complete with an error, or report progress, it is necessary for the rest of the code in the initializer to eventually call one of the dispatchers. These dispatchers, inside the promise, then loop through and call any complete/error/progress methods that have been given to that promise's then or done methods. Therefore, if you don't call a dispatcher at all, there is no completion, and this is exactly the behavior you're seeing.
Using WinJS.Promise.as is similar in that it wraps a value inside a promise. In your case, if you pass a function to WinJS.promise.as, what you'll get is a promise that's fulfilled with that function value as a result. You do not get async execution of the function.
To achieve async behavior you must either use setTimeout/setInterval (or the WinJS scheduler in Windows 8.1) to do async work on the UI thread, or use a web worker for a background thread and tie its completion (via a postMessage) into a promise.
Here's a complete example of creating a promise using the constructor, handling complete, error, and progress cases (as well as cancellation):
function calculateIntegerSum(max, step) {
if (max < 1 || step < 1) {
var err = new WinJS.ErrorFromName("calculateIntegerSum", "max and step must be 1 or greater");
return WinJS.Promise.wrapError(err);
}
var _cancel = false;
//The WinJS.Promise constructor's argument is a function that receives
//dispatchers for completed, error, and progress cases.
return new WinJS.Promise(function (completeDispatch, errorDispatch, progressDispatch) {
var sum = 0;
function iterate(args) {
for (var i = args.start; i < args.end; i++) {
sum += i;
};
//If for some reason there was an error, create the error with WinJS.ErrorFromName
//and pass to errorDispatch
if (false /* replace with any necessary error check -- we don’t have any here */) {
errorDispatch(new WinJS.ErrorFromName("calculateIntegerSum", "error occurred"));
}
if (i >= max) {
//Complete--dispatch results to completed handlers
completeDispatch(sum);
} else {
//Dispatch intermediate results to progress handlers
progressDispatch(sum);
//Interrupt the operation if canceled
if (!_cancel) {
setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });
}
}
}
setImmediate(iterate, { start: 0, end: Math.min(step, max) });
},
//Cancellation function
function () {
_cancel = true;
});
}
This comes from Appendix A ("Demystifying Promises") of my free ebook, Programming Windows Store Apps in HTML, CSS, and JavaScript, Second Edition (in preview), see http://aka.ms/BrockschmidtBook2.
You would, in your case, put your data initialization code in the place of the iterate function, and perhaps call it from within a setImmediate. I encourage you to also look at the WinJS scheduler API that would let you set the priority for the work on the UI thread.
In short, it's essential to understand that new WinJS.Promise and WinJS.Promise.as do not in themselves create async behavior, as promises themselves are just a calling convention around "results to be delivered later" that has nothing inherently to do with async.

Mechanics behind Javascript callbacks being asynchronous

I'm having a bit of trouble understanding the mechanics of JS callbacks. I have a fair idea of how callbacks can be used in JS, but I do not understand how a callback is asynchronous.
For e.g., if my understanding is correct, a callback is of the nature:
db.query(param1, param2 , callback_fn1(){..} );
And the implementation of db.query() is along the lines of :
db.prototype.query = function(p1 , p2 , callback ){
//some code
callback();
}
How does the above implementation make db.query an asynchronous function? Does this not mean that a function called callback is passed to query and that function is called inside query? It looks like query is just another synchronous function. Could someone help me understand what I'm overlooking here? Thanks!
The code sample you've shown is actually still synchronous because is instructed to run immediately. An asynchronous callback is a callback that doesn't immediately need to be executed, so it doesn't block the event loop until you instruct it to run.
The most common way in Node.js to do this is with process.nextTick() which runs a specified function when the event loop call stack is empty. Here's an example:
var async = function(args, callback) {
// do some work
process.nextTick(function() {
callback(val);
});
};
Then we call the function like this:
async(args, function(val) {
console.log(val);
});
console.log('end');
In this example, the function async() and console.log('end') are added to the call stack. The call stack empties once both of those functions are run, and once it's empty, console.log(val) then runs.
If you're still confused, think of process.nextTick() as an optimized version of this code:
var fn = function() {};
setTimeout(fn, 0);
It basically means "run this function as soon as possible when you are not busy".
Edit: I just now realized the question is tagged with node.js. My answer is more about Javascript in the browser, #hexacyanide's answer is more about node.js. I guess knowing both doesn't hurt, though!
The way you posted it the code will indeed be blocking. For asynchronous behavior there are a few things you can utilize, such as
setTimeout and setInterval
Built-in, asynchronous methods such as from the FileReader API
Ajax requests
Web workers (see #html5rocks)
Your example code could be written as follows (fiddle):
function doStuff(callback) {
setTimeout(function () {
for (var i = 0; i < 1000; i++) {
// do some busy work
var x = Math.sqrt(i);
}
callback();
}, 0);
}
console.log('start');
doStuff(function () {
console.log('callback called');
});
console.log('after doStuff()');
The setTimeout call will allow the Javascript interpreter/compiler (however exactly they work these days) to run the function in a non-blocking matter which is why (most likely), you will see the output
start
after doStuff()
callback called
Note that asynchronousity is different from multi-threading. Javascript is still single-threaded (with the exception of web workers!).
A more in-depth explanation can be found for example here

How to write a node.js function that waits for an event to fire before 'returning'?

I have a node application that is not a web application - it completes a series of asynchronous tasks before returning 1. Immediately before returning, the results of the program are printed to the console.
How do I make sure all the asynchronous work is completed before returning? I was able to achieve something similar to this in a web application by making sure all tasks we completed before calling res.end(), but I haven't any equivalent for a final 'event' to call before letting a script return.
See below for my (broken) function currently, attempting to wait until callStack is empty. I just discovered that this is a kind of nonsensical approach because node waits for processHub to complete before entering any of the asynchronous functions called in processObjWithRef.
function processHub(hubFileContents){
var callStack = [];
var myNewObj = {};
processObjWithRef(samplePayload, myNewObj, callStack);
while(callStack.length>0){
//do nothing
}
return 1
}
Note: I have tried many times previously to achieve this kind of behavior with libraries like async (see my related question at How can I make this call to request in nodejs synchronous?) so please take the answer and comments there into account before suggesting any answers based on 'just use asynch'.
You cannot wait for an asynchronous event before returning--that's the definition of asynchronous! Trying to force Node into this programming style will only cause you pain. A naive example would be to check periodically to see if callstack is empty.
var callstack = [...];
function processHub(contents) {
doSomethingAsync(..., callstack);
}
// check every second to see if callstack is empty
var interval = setInterval(function() {
if (callstack.length == 0) {
clearInterval(interval);
doSomething()
}
}, 1000);
Instead, the usual way to do async stuff in Node is to implement a callback to your function.
function processHub(hubFileContents, callback){
var callStack = [];
var myNewObj = {};
processObjWithRef(samplePayload, myNewObj, callStack, function() {
if (callStack.length == 0) {
callback(some_results);
}
});
}
If you really want to return something, check out promises; they are guaranteed to emit an event either immediately or at some point in the future when they are resolved.
function processHub(hubFileContents){
var callStack = [];
var myNewObj = {};
var promise = new Promise();
// assuming processObjWithRef takes a callback
processObjWithRef(samplePayload, myNewObj, callStack, function() {
if (callStack.length == 0) {
promise.resolve(some_results);
}
});
return promise;
}
processHubPromise = processHub(...);
processHubPromise.then(function(result) {
// do something with 'result' when complete
});
The problem is with your design of the function. You want to return a synchronous result from a list of tasks that are executed asynchronously.
You should implement your function with an extra parameter that will be the callback where you would put the result (in this case, 1) for some consumer to do something with it.
Also you need to have a callback parameter in your inner function, otherwise you won't know when it ends. If this last thing is not possible, then you should do some kind of polling (using setInterval perhaps) to test when the callStack array is populated.
Remember, in Javascript you should never ever do a busy wait. That will lock your program entirely as it runs on a single process.
deasync is desinged to address your problem exactly. Just replace
while(callStack.length>0){
//do nothing
}
with
require('deasync').loopWhile(function(){return callStack.length>0;});
The problem is that node.js is single-threaded, which means that if one function runs, nothing else runs (event-loop) until that function has returned. So you can not block a function to make it return after async stuff is done.
You could, for example, set up a counter variable that counts started async tasks and decrement that counter using a callback function (that gets called after the task has finished) from your async code.
Node.js runs on A SINGLE threaded event loop and leverages asynchronous calls for doing various things, like I/O operations.
if you need to wait for a number of asynchronous operations to finish before executing additional code
you can try using Async -
Node.js Async Tutorial
You'll need to start designing and thinking asynchronously, which can take a little while to get used to at first. This is a simple example of how you would tackle something like "returning" after a function call.
function doStuff(param, cb) {
//do something
var newData = param;
//"return"
cb(newData);
}
doStuff({some:data}, function(myNewData) {
//you're done with doStuff in here
});
There's also a lot of helpful utility functions in the async library available on npm.

Categories

Resources