For a couple of years, I was dealing with a part time problem where some DOM elements loaded with jquery html function were not accessible immediately after the function call (The behaviour was a bit like executing a function without waiting for the document ready event). Even though .html() is suppose to be synchronous, this SO answer (and also this one) suggests using the promise of the html function:
$('#divId').html("<h1>hello</h1>").promise().done(function(){
//Callback
});
A promise could make sense in such context but what intrigues me about this promise is that it will also be returned with every jquery's object:
$('#divId').promise().done(function(){
//Will also be called...
});
Since I couldn't find anything about it in the documentation of the html function, I was wondering what was the real purpose of this promise and if it is used correctly in this context.
The two methods are not related. The reason people often suggest this is because someone found out that they could use .promise().done() to make their code that has a race condition work. It worked for the same reason wrapping the same code in setTimeout(fn, 0) would make it work; it pushes it off to the callback queue to be ran later, likely after the browser performs a render or after some other async callback completes.
.html is synchronous, does not have a callback, and does not need a callback. However, the browser's renderer is asynchronous, so it won't render the change until after the callstack is clear. Using .promise pushes the callback off to the callback queue, thus running the code after a render which resolves the race condition or async logic flaw.
.promise() used on a jquery collection returns a promise that will resolve once all currently running jquery animations are complete. If there are no currently running animations, the promise will resolve immediately and the callback will be pushed to the callback queue to be called once the stack is clear.
It's nothing more than a bandaid. I'd suggest not using it, and instead fixing whatever async logic flaw is causing it to be the solution.
Related
So I kind of understand the JS event loop, but still have a few questions. Here is my scenario and a few questions.
So let's say I have these functions:
function1 - reads an absolute huge file.
function2 - console.log("Hey");
function3 - console.log("What's up");
The way I am understanding this, and correct me if I'm wrong, what would happen is that the function1, function2, and function3, would be added to the queue. Then function1 would be added to the call stack followed by the next two functions.
Now the part where I'm confused is because the first function is going to take an extremely long time what happens to it? Does it get pushed somewhere else so that the next two functions are executed? I think the answer to this is that the only way it gets pushed somewhere else so that you can continue running is to make it an asynchronous function. And the way you make it a asynchronous function is either by using a callback function or promises. If this is the case how does it know that this is a asynchronous function? And where does it get pushed to so that the other two functions can be executed since they are relatively simple?
I think I answered the question myself but I keep confusing myself so if somebody could explain in extremely simple terms that would be great and sorry for the extremely stupid question.
Ordinary function calls are not pushed on the event queue, they're just executed synchronously.
Certain built-in functions initiate asynchronous operations. For instance, setTimeout() creates a timer that will execute the function asynchronously at a future time. fetch() starts an AJAX request, and returns a promise that will resolve when the response is received. addEventListener() creates a listener that will call the function when the specified event occurs on an element.
In all these cases, what effectively happens is that the callback function is added to the event queue when the corresponding condition is reached.
When one of these functions is called, it runs to completion. When the function returns, the event loop pulls the next item off the event queue and runs its callback, and so on.
If the event queue is empty, the event loop just idles until something is added. So when you're just starting at a simple web page, nothing may happen until you click on something that has an event listener, then its listener function will run.
In interactive applications like web pages, we try to avoid writing functions that take a long time to run to completion, because it blocks the user interface (other asynchronous actions can't interrupt it). So if you're going to read a large file, you use an API that reads it incrementally, calling an event listener for each block. That will allow other functions to run between processing of each block.
There's nothing specific that identifies asynchronous functions, it's just part of the definition of each function. You can't say that any function that has a callback argument is asynchronous, because functions like Array.forEach() are synchronous. And promises don't make something asychronous -- you can create a promise that resolves synchronously, although there's not usually a point to it (but you might do this as a stub when the caller expects a promise in the general case). The keyword async before a function definition just wraps its return value in a promise, it doesn't actually make it run asynchronously.
In Javascript, the callback (of the awaited async function) runs only when the call stack is empty. If there are multiple callbacks, then they are queued (in the event loop queue) such that only 1 callback runs in its entirety before the next callback gets change to run.
In case of C# (assuming ConfigureAwait is not set to false - that is - the callabck will run in the same thread; also assuming there is syncronization context [winforms]):
Does the callback run immediately without waiting for call stack to be empty?
Suppose there are multiple callbacks queued, then while 1 callback is running, and another callback is ready for execution, then does the running callback suspend while the new callback wants to run? Or is it sequential?
The answer is that it depends on the current SynchronizationContext and, if that is null, the current TaskScheduler.
When the awaited Task completes, and you have configured the Awaitable to capture the context and recover on it, then almost certainly that continuation cannot continue immediately (the thread is likely busy executing something else). All that can be done is to schedule the continuation for later execution on the current SynchronizationContext, which is done by calling SynchronizationContext.Post().
How this Post method is implemented depends on the SynchronizationContext (which is abstract). If you are using WPF, the SynchronizationContext is a DispatcherSynchronizationContext. There, Post is implemented by a call to Dispatcher.BeginInvoke() with DispatcherPriority.Normal.
In other words, your continuation gets queued on the dispatcher for later execution with normal priority. Other delegates may have higher priority (e.g. DispatcherPriority.Input), but eventually your delegate gets executed on the dispatcher.
Two things to notice:
BeginInvoke simply queues your delegate. It does not execute it right away. In other words, queuing your delegate is really fast.
The above explanation should illustrate why async-await is just syntactic sugar. You could achieve all these calls yourself, but the compiler does it for you, making your code flow more naturally.
im currently working on a project that uses a few microservices and one of them must do the same thing over and over again.
The code looks like this:
refresh: function(){
return somePromise
.then(doA)
.then(doB)
.then(doC)
.catch(error)
}
So currently another function calls this "refresh" function with setInterval every second.
The problem is that because of the async nature of these calls in refresh method, some bugs appear.
I changed the code to call the 'refresh' method again recursively in the last '.then' statement and removed the setInterval.
refresh: function(){
return somePromise
.then(doA)
.then(doB)
.then(doC)
.then(refresh)
}
Nowthe bugs appear to be gone and everything works perfectly.
My question is:
Is this a good practice? Are there any memory problems with calling the "refresh" method recursively in the last '.then' statement?
Is this a good practice?
If you just want it to repeat whenever it finishes and make sure the next iteration doesn't start before the previous one finishes, this is a perfectly fine practice (much better than setInterval()). Your looping stops if there's a rejection anywhere so you may want to code what should happen with a .catch().
Are there any memory problems with calling the "refresh" method recursively in the last '.then' statement?
No. There are not. Since .then() is always called asynchronously, the stack always gets to unwind and since you presumably have async operations in your chain, there should be time for normal garbage collection.
See Building a promise chain recursively in javascript - memory considerations for more discussion of memory consumption during the looping.
FYI, this must be pseudo-code because a function defined as a property refresh: function() {} won't be directly callable with .then(refresh). So, I'm assuming you did that properly in your real code.
I have a an angular event like this:
$rootScope.$broadcast("postData");
doSomething();
however, doSomething() must wait for postData to complete before execution.
I would normally do something like:
$rootScope.$broadcast("postData").then(function(){
doSomething();
});
But apparently this isn't a thing in angular...Any ideas?
I would like to point-out that the previous solutions are not possible to be implemented where we don't have a handle on the async call to put a callback/promise/throw an event to solve the issue. The async call may be library function like for example setTimeout and we just cant use the previous solutions to fix the flow.
Here's my solution:
Put doSomething(); in an setTimeout with the time interval set to 0,
$rootScope.$broadcast("postData");
setTimeout(function(){
doSomething();}
, 0);
As simple as that!
settimeout makes dosomething() also to be asynchronous and this makes both the asynchronous operations happen one after the other(asynchronously). How? The explanation follows, but first note that the dosomething() is in a setTimout of interval 0 ms. One may obviously think that dosomething() shall be executed right-away (after 0 ms (actually default minimum time interval in javascript is 4 ms, so 0 ms becomes 4 ms)) before the postData event is broadcast-ed and serviced.
The answer is no!
Settimeout doesn't guarantee that the callback function passe inside it shall surely get executed after the specified interval. The specified interval is just the minimum interval needed after which the callback can be executed. SetTimeOut is an asynchronous call. if there are any other async operation waiting in the pipeline already, javascript runs them first.
For understanding how all this happen you need to understand what is an event loop in javascript.
Javascript runtime is single threaded, it just have one call stack, meaning it runs the code sequentially as it is written. Then how on earth does it implement asyncronicity?
So this is what happens under the hood when the javascript run-time encounters an operation that is asyncronous (like an API call, http call, settimeout, event broadcast etc). Please note these functions are not provided in our native javascipt run time engine (for example chromes V8 engine), instead they are provided by the browser (known as webAPIs), which are basically threads that you can make call to and they fork off an independent path of execution, separate from the javascript run-time execution flow, and thats how concurrency is actually achieved.
The question arises that Javascript run time is still single threaded. So how does these webAPI inturrpt the runtime flow and provide their results when they are complete? They can not just prompt the javascript runtime anytime when they are finished and provide their results to it? There must be some mechanism.
So javascript just makes the call to these webAPI's and does not wait for the output of the call. It simply goes on and execute the code that follows the call, and thats how the dosomething() in the problem, gets executed before the postDate event is listened and served).
Meanwhile the forked thread processes the http call or the setTimeout or handle the event etc, whatever the async call was made for. And when its done, the callback is pushed onto a event queue (task queue) (Note that multiple callback returns can be pushed into this queue.). But they are not run right away.
The javascript runtime waits for the call stack to get empty first. When there is nothing for the javascript runtime to execute the async calls callback function are popped out from the task queue, one by one and executed.
So in essence if we can just make dosomething() async, it will get executed after the 1st async is completed. Thats what I did. The settimeout callback gets pushed onto the event queue/task queue. Javascript call stack gets empty. The call back for postData event broadcast gets served. Then dosomething() gets a chance to execute.
You could $broadcast the event, listen for it in your other controller with $on, and $emit another event on completion, and listen for it in your original controller so you know when it is finished.
I would not recommend this approach. Instead use a service.
Emit and broadcast are coupling your mechanisms for communication to the view because the $scope is fundamentally a fabric for data-binding.
The services approach is far more maintainable and can communicate between services in addition to controllers.
Im assuming the broadcast of 'postData' is defining the end of a funciton.
If you use the $q angular service this can be accomplished easily by creating asynchronous functions.
function postData() {
var deferred = $q.defer();
//Do your asynchronous work here that post data does
//When the asynchronous work is done you can just resolve the defer or
//you can return data with resolve. Passing the data you want
//to return as a param of resolve()
deferred.resolve();
//return
return deferred.promise;
}
When you call postData now you can now use the then method to run doSomething() after postData() is done.
postData().then(function(data) {
doSomething();
}, function (err){
//if your ansyncronous function return defer.reject() instead of defer.resolve() you can catch the error here
};
Heres the angular documentation for $q
Heres a plunk to show you a simple example
This isn't how events works, you can't wait for events to complete.
Why won't you fire 'postData', let the consumers of this event do whatever they does, and then wait for another event and execute 'doSomething' once you receive it?
This way, once the consumer of 'postData' finish processing the event, he can fire another event which you can consume and execute your 'doSomething' when you receive it.
Very simple question: suppose I have the following js/jquery code
doSomething();
$.get(url, callback);
doSomethingElse();
I understand that right after the GET request is sent doSomethingElse() starts being executed. Now suppose that the server's reply arrives while doSomethingElse() is executing. What happens?
Does the callback run in a separate thread in parallel to doSomethingElse()?
Does the execution of doSomethingElse() pause until the callback runs and returns?
Does the callback only get called once doSomethingElse() has returned?
Thank you for any insight!
lara
No, JavaScript in web browsers is single-threaded, by design. That means that although the ajax call may start immediately (and be processed by another thread in the browser), your callback won't happen until the JavaScript interpreter is next idle. Things to do get queued up waiting for the interpreter to become idle and process them.
Edit Answering your specific questions:
Does the callback run in a separate thread in parallel to doSomethingElse()?
No, the callback will run in the same logical thread as doSomethingElse. (It would be implementation-dependant whether that's the same actual underlying OS thread, but you have no way of knowing and you don't care; logically, it's the same thread.)
Does the execution of doSomethingElse() pause until the callback runs and returns?
By default, the get will be asynchronous, so no. doSomethingElse initiates the request, but then continues. (It's possible to do a synchronous get via the underlying XmlHttpRequest mechanism, but it's a very bad idea -- tends to lock up the UI of the browser completely while the request is running, which is ugly -- and I don't know how you do it with jQuery.)
Does the callback only get called once doSomethingElse() has returned?
With an asynchronous get (the usual kind), you can be certain that doSomethingElse will finish before the callback gets called, yes. This is because the JavaScript interpreter will only do one thing at a time, and it doesn't switch to doing a new thing until it's done with the current one. So although doSomethingElse triggers the get (and the get may be processed by other, non-JavaScript threads in parallel to JavaScript), your callback won't happen until after the interpreter is done with doSomethingElse and anything that called it.
I wouldn't be surprised if at some point we start getting multiple threads in browser-based JavaScript, but if and when we do, it'll have to be explicit, since we all happily assume one thread for the moment.
To all intents and purposes there are no threads in JS, therefore execution does not happen on a separate thread.
What web APIs do do is make use of asynchronous callbacks, and that's what is happening here -- get() returns immediately, your callback function will be called once the load is complete and there is no other JS code running.
No, there is only one thread of control for Javascript. The currently executing function will continue running until it completes, then the callback will be invoked once it is ready.
So to specifically answer your question, the callback only gets called once doSomethingElse() has returned. Assuming, of course, that the GET request is successful - if an error occurrs then the callback will never be executed.
Here is a pretty good article that illustrates how this works.
http://www.javascriptkata.com/2007/06/12/ajax-javascript-and-threads-the-final-truth/
I honestly don't know the answer, but I wouldn't place any code in doSomethingElse() that is dependent on something that callback() does. I know that doSomethingElse() will always run first, but as far as timing/thread issues I'm not sure.