How to write simple asynchronous function in javascript - javascript

I want to call a javascript function that takes a long time (5 seconds) to finish without freezing my client's browser. They click the button to start the operation, then they should be notified when it finishes. Currently I have written something like
$(document).ready(function(){
$('#tokenbutton').click(function(){
// IMMEDIATE EFFECT
$('#tokenbutton').attr("disabled",true).val("Computing...");
var callback = function(resultsFromExpensiveOperation){
// CALLBACK EFFECTS
$('#tokenbutton').val("Token computed");
$('#submitbutton').attr("disabled",false);
// ...
};
// FREEZES BROWSER
doExpensiveOperation(callback);
});
});
and
doExpensiveOperation = function(callback){
// ...
//var results = ...
callback(results);
};
but this freezes my browser when I run it. How can I change it so this doesn't freeze my browser?

There are no real asynchronous is javascript, thus no multi thread or anything like that. There is a way to make long running function not freeze the browser in certain cases though.
You can use the setInterval or setTimeout function to do small bits of your long running task at a time, thus each bit takes a fraction of a second and then the ui becomes responsive again for a fraction of a second until the next bit runs. This functionally makes the ui stay responsive and does not add much time (if any) onto the processing of the code. For example.
long running code
function doSomething(){
for(var x = 0; x < 10000; x++){
// do something
}
}
// doing it like this could take forever and lock up the browser
broken up code
var total = 0;
setTimeout(doSomething, 4);
function doSomething(){
for(total = total; total + 100 < 100; total++){
// do something
}
if(total < 10000){
setTimeout(doSomething, 4);
}
}
// doing it like this stops the browser from freezing but does not save any time.
A few things,
I put a time of 4 ms into the setTimout because that is actually the lowest value js will except, even if you put 1 it defaults to 4.
I used a setTimeout pattern instead of a setInterval to prevent the next interval from running before the previous on finishes.
And lastly this pattern does not work for everything. It lends itself best to loop and sequence based operations.
Hope it helps

Use Case
Create a non-Ajax separate process that returns data to a callback.
Solution
Requirements
Browser must:
Support HTML5
Support Web Workers
Structure
Create a separate file for your separate threaded process with the logic. This file must contain the following code:
postMessage( //data )
Code
if(typeof(Worker) === "function") {
var worker = new Worker(//uri to js file);
worker.onmessage = function(event){
// my call back.
};
}

Related

Allow running setInterval more than once per millisecond in nodejs

I have a node script which is supposed to utilize all the CPU resources a single node process could get. But I found setInterval to be too slow.
And sure enough I found this in the documentation:
When delay is larger than 2147483647 or less than 1, the delay will be
set to 1.
source: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
Now I wonder if there is a way to reduce the limit further or if there is an alternative function that I could use.
I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
Edit:
Again: I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
I'm not sure why this is so hard to understand.
While a normal loop is running, you are blocking the execution of everything else. It doesn't matter if you put the loop in another asynchronously executed function.
What does this mean?
Let's look at some examples:
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
while (true) {
// do whatever
}
What will this code do? It will block everything. console.log('a') will not be executed continuously.
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
setTimeout(()=>{
while (true) {
// do whatever
}
}, 1)
This will also block the execution of the intervals as soon as the while loop starts.
I believe the question belongs to node rather than to browser. You can use some of the following options (recursively/in loop) for reducing your delay time.
setImmediate
setImmediate - Schedules the "immediate" execution of the callback after I/O events' callbacks. Returns an Immediate for use with clearImmediate().
When multiple calls to setImmediate() are made, the callback functions are queued for execution in the order in which they are created. The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.
It's from node guides:
setImmediate and setTimeout are similar, but behave in different
ways depending on when they are called.
setImmediate() is designed to execute a script once the current poll phase completes.
setTimeout() schedules a script to be run after a minimum threshold in ms has elapsed.
process.nextTick
The process.nextTick() method adds the callback to the "next tick
queue". Once the current turn of the event loop turn runs to
completion, all callbacks currently in the next tick queue will be
called.
From node guide
We recommend developers use setImmediate() in all cases because it's
easier to reason about (and it leads to code that's compatible with a
wider variety of environments, like browser JS.)
Thanks to Josh Lin for the idea to just run multiple intervals. I ended up with two simple wrapper functions for setInterval and clearInterval:
function setInterval2(cb,delay) {
if (delay >= 1)
return [setInterval(cb,delay)];
var intervalArr = [];
var intervalCount = Math.round(1/delay);
for (var i=0; i<intervalCount; i++)
intervalArr.push(setInterval(cb,1));
return intervalArr
}
function clearInterval2(intervalArr) {
intervalArr.forEach(clearInterval);
}
It works just like the original functions:
var count = 0;
// run interval every 0.01 milliseconds:
var foo = setInterval2(function(){
count++;
},0.01);
// stop execution:
clearInterval2(foo)
1 setInterval multiple times run more!
let count = 0,
by = 100,
_intervals = [],
timelimit = 100
for (let i = 0; i < by; i++) {
_intervals[i] = setInterval(() => count++, 1)
}
setTimeout(() => {
_intervals.forEach(x => clearInterval(x))
console.log(`count:${count}`)
}, timelimit)
2.setTimeout recurser run less!
let count = 0,
go = true
recurser()
setTimeout(() => {
go = false
console.log(`count:${count}`)
}, 100)
function recurser() {
count++
go && setTimeout(recurser)
}
3.requestAnimationFrame run less!
let count = 0,
go = true,
timelimit = 100
step()
setTimeout(() => {
go = false,
console.log(`count:${count}`)
}, timelimit)
function step() {
count++
go && requestAnimationFrame(step)
}
so as I know ,run setInterval multiple times, and I believe while will count more
You ask if it is possible to
run setInterval more than once per millisecond in nodejs
As you note in your question, this is not possible with setInterval, since there is always a minimum delay of at least 1 ms in node.js. In browsers, there is often a minimum delay of at least 10 ms.
However, what you want to achieve—to repeatedly run CPU-intensive code without unnecessary delay—is possible in other ways.
As noted in the answer by The Reason, setImmediate is a good option available in node.js. As setImmediate has limited browser support, and is unlikely to be widely supported in the future, there is another approach that also works in browsers.
While browsers enforce a minimum delay for setInterval and setTimeout, the delay for setTimeout is enforced from when the timer is set, not when it is run. If we use setTimeout repeatedly to call CPU-intensive code, we can make sure that a timer is always set 10–15 ms in advance (if the code takes at least 10–15 ms to run), thus reducing the actual delay to 0 ms.
The demo snippet below borrows code from this answer to demonstrate how the use of timers set in advance may make the delay smaller than what is enforced. In the browsers I tested, this usually results in a 0 ms delay.
// First: repeat runCPUForAtLeast50ms() 10 times
// with standard repeated setTimeouts and enforced delays
testTimeout(10, function(){
// Then: repeat runCPUForAtLeast50ms() 10 times
// using a repeated set of queued setTimeouts
// circumventing the enforced delays
testTimeout(10, false, true);
});
function testTimeout(repetitions, next, multiple) {
var delays = [];
var lastCheck;
var extraTimers;
function runner() {
if(lastCheck){
delays.push((+new Date) - lastCheck);
}
if(repetitions > 0) {
//process chunk
runCPUForAtLeast50ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((multiple?
'Repeated multiple timers delays: ' :
'Repeated single timer delays: ') + delays.join(', '));
//invoke next() function if provided
next && next();
}
repetitions--;
lastCheck = +new Date;
}
setTimeout(runner);
if(multiple){
// make sure that there are always a fixed
// number of timers queued by setting extra timers
// at start
extraTimers = 10;
while(extraTimers--)
setTimeout(runner);
}
}
function runCPUForAtLeast50ms() {
var d = (+new Date) + 50;
while(+new Date < d);
}
I think you can solve your problem using async module... a way could be:
async.parallel([
(callback) => {
// do normal stuff
},
(callback) => {
// do your loop
}
], (err, results) => {
// ...
});
But take into account this note from the official documentation...
Note: parallel is about kicking-off I/O tasks in parallel, not about
parallel execution of code. If your tasks do not use any timers or
perform any I/O, they will actually be executed in series. Any
synchronous setup sections for each task will happen one after the
other. JavaScript remains single-threaded.
In short answer, you can't. There are some limitation of Javascript/Node as it is a single thread application. That's why you have async interrupts.
The long answer:
From the computer architecture's perspective, modern CPU and Kernel scheduling is not deterministic. If you want such fine grain control, I would suggest you look at MCU and embedded solutions that does not have a kernel scheduler. Because, your OS have many other processes and Kernel processes that takes up CPU time, so kernel scheduler have to keep scheduling different processes to be run on the CPU and meet many different demands.
Even with the set 1ms, when you try to measure, it is probably not 1ms (exact time depends on OS, hardware and amount of processes running on your computer).
Now, if you want to use all CPU resources, not possible.
But if you want to utilize as much as resources as possible, you can explore current programming pattern. For example, you can schedule 1 million threads (you machine probably won't be able to handle it), or some crazy large amount of processes and let your scheduler to be constantly putting process on your CPU, so there is no idle time and max out CPU utilization.
Alternatively, you can run CPU Stress tests, and those are designed to simply max out your CPU and keep it burning to high temperature -- make sure you have the cooling solution in place.

Is using a while loop a good waiting strategy in a Firefox Restartless Extension?

I have a bootstrapped extension which interacts with the chrome part of Firefox (i.e. even before the content loads), and needs to query an SQLite database for some check. I would prefer a sync call. But, since a sync call is bad in terms of performance and can cause possible UI issues, I need to make an async DB call.
My use case is such:
Make aysnc call to database
Once completed do further processing
Now, this can be easily handled by placing 'further processing' part in handleCompletion part of executeAsync function.
But, I want the 'further processing' to be done irrespective of this statement being executed i.e. This DB lookup may or may not happen. If it doesn't happen well and good, go ahead. If it does I need to wait.
So, I am using a flag based strategy; I set a flag handleCompletionCalled in handleError & handleCompletion callback to true.
In the further processing part, I do a
while(handleCompletionCalled) {
// do nothing
}
//further processing
Is this a good strategy or can I do something better ( I don't really want to use Observers, etc. for this since I have many such cases in my entire extension and my code will be filled with Observers)?
Using a while loop to wait is a seriously Bad Idea™. If you do, the result will be that you hang the UI, or, at a minimum, drive CPU usage through the roof by rapidly running though your loop a large number of times as fast as possible.1
The point about asynchronous programming is that you start an action and then another function, a callback, is executed once the activity is completed, or fails. This either allows you to start multiple actions, or to relinquish processing to some other part of the overall code. In general, this callback should handle all activity that is dependent on the completion of the asynchronous action. The callback function, itself, does not have to include the code to do the other processing. After it has done what needs to happen in response to the async action completing, it can just call another function like doOtherProcessing().
If you launch multiple asynchronous, actions you can then wait for the completion of all of them by having flags for each task and a single function that is called at the end of all the different callback functions like:
function continueAfterAllDone(){
if(task1Done && task2Done && task3Done && task4Done) {
//do more processing
}else{
//Not done with everything, yet.
return;
}
}
This could be extended to an arbitrary number of tasks by using an array, or task queue, which the function then checks to see if all of those are completed rather than a hard-coded set of tasks.
Waiting:
If you are going to have another processing path which executes, but then must wait for the completion of the asynchronous action(s), you should have the wait performed by setting up a timer, or interval. You then yield the processor for a specified period of time until you check again to see if the conditions you need to proceed have occurred.
In a bootstrapped add-on, you will probably need to use the nsITimer interface to implement a timeout or interval timer. This is needed because at the time you are running your initialization code it is possible that no <window> exists (i.e. there may be no possibility to have access to a window.setTimeout()).
If you are going to implement a wait for some other task, you could do it something like:
const Cc = Components.classes;
const Ci = Components.interfaces;
var asyncTaskIsDone = false;
var otherProcessingDone = false;
// Define the timer here in case we want to cancel it somewhere else.
var taskTimeoutTimer;
function doStuffSpecificToResultsOfAsyncAction(){
//Do the other things specific to the Async action callback.
asyncTaskIsDone = true;
//Can either call doStuffAfterOtherTaskCompletesOrInterval() here,
// or wait for the timer to fire.
doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval();
}
function doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval(){
if(asyncTaskIsDone && otherProcessingDone){
if(typeof taskTimeoutTimer.cancel === "function") {
taskTimeoutTimer.cancel();
}
//The task is done
}else{
//Tasks not done.
if(taskTimeoutTimer){
//The timer expired. Choose to either continue without one of the tasks
// being done, or set the timer again.
}
//}else{ //Use else if you don't want to keep waiting.
taskTimeoutTimer = setTimer(doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval
,5000,false)
//}
}
}
function setTimer(callback,delay,isInterval){
//Set up the timeout (.TYPE_ONE_SHOT) or interval (.TYPE_REPEATING_SLACK).
let type = Ci.nsITimer.TYPE_ONE_SHOT
if(isInterval){
type = Ci.nsITimer.TYPE_REPEATING_SLACK
}
let timerCallback = {
notify: function notify() {
callback();
}
}
var timer = Cc["#mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(timerCallback,delay,type);
return timer;
}
function main(){
//Launch whatever the asynchronous action is that you are doing.
//The callback for that action is doStuffSpecificToResultsOfAsyncAction().
//Do 'other processing' which can be done without results from async task here.
otherProcessingDone = true;
doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval();
}
Initialization code at Firefox startup:
The above code is modified from what I use for delaying some startup actions which do not have to be done prior to the Firefox UI being displayed.
In one of my add-ons, I have a reasonable amount of processing which should be done, but which is not absolutely necessary for the Firefox UI to be shown to the user. [See "Performance best practices in extensions".] Thus, in order to not delay the UI, I use a timer and a callback which is executed 5 seconds after Firefox has started. This allows the Firefox UI to feel more responsive to the user. The code for that is:
const Cc = Components.classes;
const Ci = Components.interfaces;
// Define the timer here in case we want to cancel it somewhere else.
var startupLaterTimer = Cc["#mozilla.org/timer;1"].createInstance(Ci.nsITimer);
function startupLater(){
//Tasks that should be done at startup, but which do not _NEED_ to be
// done prior to the Firefox UI being shown to the user.
}
function mainStartup(){
let timerCallback = {
notify: function notify() {
startupLater();
}
}
startupLaterTimer = startupLaterTimer.initWithCallback(timerCallback,5000
,Ci.nsITimer.TYPE_ONE_SHOT);
}
Note that what is done in startupLater() does not, necessarily, include everything that is needed prior to the ad-on being activated by the user for the first time. In my case, it is everything which must be done prior to the user pressing the add-on's UI button, or invoking it via the context menu. The timeout could/should be longer (e.g. 10s), but is 5s so I don't have to wait so long for testing while in development. Note that there are also one-time/startup tasks that can/should be done only after the user has pressed the add-on's UI button.
1. A general programming issue here: In some programming languages, if you never yield the processor from your main code, your callback may never be called. In such case, you will just lock-up in the while loop and never exit.

Animations under single threaded JavaScript

JavaScript is a single threaded language and therefore it executes one command at a time. Asynchronous programming is being implemented via Web APIs (DOM for event handling, XMLHttpRequest for AJAX calls, WindowTimers for setTimeout) and the Event queue which are managed by the browser. So far, so good! Consider now, the following very simple code:
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
...
Could someone please explain to me the underlying mechanism of the above? Since .hide() has not yet finished (the animation lasts 17 seconds) and JS engine is dealing with it and it is capable of executing one command at a time, in which way does it go to the next line and continues to run the remaining code?
If your answer is that animation creates promises, the question remains the same: How JavaScript is dealing with more than one thing at the same time (executing the animation itself, watching the animation queue in case of promises and proceeding with the code that follows...).
Moreover, I cannot explain how promises in jQuery work if they have to watch their parent Deferred object till it is resolved or rejected that means code execution and at the same time the remaining code is executed. How is that possible in a single threaded approach? I have no problem to understand AJAX calls for I know they are taken away from JS engine...
tl;dr; it would not be possible in a strictly single threaded environment without outside help.
I think I understand your issue. Let's get a few things out of the way:
JavaScript is always synchronous
No asynchronous APIs are defined in the language specification. All the functions like Array.prototype.map or String.fromCharCode always run synchronously*.
Code will always run to completion. Code does not stop running until it is terminated by a return, an implicit return (reaching the end of the code) or a throw (abruptly).
a();
b();
c();
d(); // the order of these functions executed is always a, b, c, d and nothing else will
// happen until all of them finish executing
JavaScript lives inside a platform
The JavaScript language defines a concept called a host environment:
In this way, the existing system is said to provide a host environment of objects and facilities, which completes the capabilities of the scripting language.
The host environment in which JavaScript is run in the browser is called the DOM or document object model. It specifies how your browser window interacts with the JavaScript language. In NodeJS for example the host environment is entirely different.
While all JavaScript objects and functions run synchronously to completion - the host environment may expose functions of its own which are not necessarily defined in JavaScript. They do not have the same restrictions standard JavaScript code has and may define different behaviors - for example the result of document.getElementsByClassName is a live DOM NodeList which has very different behavior from your ordinary JavaScript code:
var els = document.getElementsByClassName("foo");
var n = document.createElement("div");
n.className = "foo";
document.body.appendChild(n);
els.length; // this increased in 1, it keeps track of the elements on the page
// it behaves differently from a JavaScript array for example.
Some of these host functions have to perform I/O operations like schedule timers, perform network requests or perform file access. These APIs like all the other APIs have to run to completion. These APIs are by the host platform - they invoke capabilities your code doesn't have - typically (but not necessarily) they're written in C++ and use threading and operating system facilities for running things concurrently and in parallel. This concurrency can be just background work (like scheduling a timer) or actual parallelism (like WebWorkers - again part of the DOM and not JavaScript).
So, when you invoke actions on the DOM like setTimeout, or applying a class that causes CSS animation it is not bound to the same requirements your code has. It can use threading or operating system async io.
When you do something like:
setTimeout(function() {
console.log("World");
});
console.log("Hello");
What actually happens is:
The host function setTimeout is called with a parameter of type function. It pushes the function into a queue in the host environment.
the console.log("Hello") is executed synchronously.
All other synchronous code is run (note, the setTimeout call was completely synchronous here).
JavaScript finished running - control is transferred to the host environment.
The host environment notices it has something in the timers queue and enough time has passed so it calls its argument (the function) - console.log("World") is executed.
All other code in the function is run synchronously.
Control is yielded back to the host environment (platform).
Something else happens in the host environment (mouse click, AJAX request returning, timer firing). The host environment calls the handler the user passed to these actions.
Again all JavaScript is run synchronously.
And so on and so on...
Your specific case
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
Here the code is run synchronously. The previous command has terminated, but it did not actually do much - instead it scheduled a callback on the platform a(in the .hide(17000) and then executed the console.log since again - all JavaScirpt code runs synchronously always.
That is - hide performs very little work and runs for a few milliseconds and then schedules more work to be done later. It does not run for 17 seconds.
Now the implementation of hide looks something like:
function hide(element, howLong) {
var o = 16 / howLong; // calculate how much opacity to reduce each time
// ask the host environment to call us every 16ms
var t = setInterval(function
// make the element a little more transparent
element.style.opacity = (parseInt(element.style.opacity) || 1) - o;
if(parseInt(element.style.opacity) < o) { // last step
clearInterval(t); // ask the platform to stop calling us
o.style.display = "none"; // mark the element as hidden
}
,16);
}
So basically our code is single threaded - it asks the platform to call it 60 times a second and makes the element a little less visible each time. Everything is always run to completion but except for the first code execution the platform code (the host environment) is calling our code except for vice versa.
So the actual straightforward answer to your question is that the timing of the computation is "taken away" from your code much like in when you make an AJAX request. To answer it directly:
It would not be possible in a single threaded environment without help from outside.
That outside is the enclosing system that uses either threads or operating system asynchronous facilities - our host environment. It could not be done without it in pure standard ECMAScript.
* With the ES2015 inclusion of promises, the language delegates tasks back to the platform (host environment) - but that's an exception.
You have several kind of functions in javascript:
Blocking and non blocking.
Non blocking function will return immediately and the event loop continues execution while it work in background waiting to call the callback function (like Ajax promises).
Animation relies on setInterval and/or setTimeout and these two methods return immediately allowing code to resume. The callback is pushed back into the event loop stack, executed, and the main loop continues.
Hope this'll help.
You can have more information here or here
Event Loop
JavaScript uses what is called an event loop. The event loop is like a while(true) loop.
To simplify it, assume that JavaScript has one gigantic array where it stores all the events. The event loop loops through this event loop, starting from the oldest event to the newest event. That is, JavaScript does something like this:
while (true) {
var event = eventsArray.unshift();
if (event) {
event.process();
}
}
If, during the processing of the event (event.process), a new event is fired (let's call this eventA), the new event is saved in the eventsArray and execution of the current continues. When the current event is done processing, the next event is processed and so on, until we reach eventA.
Coming to your sample code,
$('#mybox').hide(17000);
console.log('Previous command has not yet terminated!');
When the first line is executed, an event listener is created and a timer is started. Say jQuery uses 100ms frames. A timer of 100ms is created, with a callback function. The timer starts running in the background (the implementation of this is internal to the browser), while the control is given back to your script. So, while the timer is running in the background, your script continues to line two. After 100ms, the timer finishes, and fires an event. This event is saved in the eventsArray above, it does not get executed immediately. Once your code is done executing, JavaScript checks the eventsArray and sees that there is one new event, and then executes it.
The event is then run, and your div or whatever element it is moves a few pixels, and a new 100ms timer starts.
Please note that this is a simplification, not the actual working of the whole thing. There are a few complications to the whole thing, like the stack and all. Please see the MDN article here for more info.
Could someone please explain to me the underlying mechanism of the
above? Since .hide() has not yet finished (the animation lasts 17
seconds) and JS engine is dealing with it and it is capable of
executing one command at a time, in which way does it go to the next
line and continues to run the remaining code?
jQuery.fn.hide() internally calls jQuery.fn.animate which calls jQuery.Animation which returns a jQuery deferred.promise() object; see also jQuery.Deferred()
The deferred.promise() method allows an asynchronous function to
prevent other code from interfering with the progress or status of its
internal request.
For description of Promise see Promises/A+ , promises-unwrapping , Basic Javascript promise implementation attempt ; also , What is Node.js?
jQuery.fn.hide:
function (speed, easing, callback) {
return speed == null || typeof speed === "boolean"
? cssFn.apply(this, arguments)
: this.animate(genFx(name, true), speed, easing, callback);
}
jQuery.fn.animate:
function animate(prop, speed, easing, callback) {
var empty = jQuery.isEmptyObject(prop),
optall = jQuery.speed(speed, easing, callback),
doAnimation = function () {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation(this, jQuery.extend({},
prop), optall);
// Empty animations, or finishing resolves immediately
if (empty || jQuery._data(this, "finish")) {
anim.stop(true);
}
};
doAnimation.finish = doAnimation;
return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation);
}
jQuery.Animation:
function Animation(elem, properties, options) {
var result, stopped, index = 0,
length = animationPrefilters.length,
deferred = jQuery.Deferred().always(function () {
// don't match elem in the :animated selector
delete tick.elem;
}),
tick = function () {
if (stopped) {
return false;
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max(0, animation.startTime + animation.duration - currentTime),
// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
temp = remaining / animation.duration || 0,
percent = 1 - temp,
index = 0,
length = animation.tweens.length;
for (; index < length; index++) {
animation.tweens[index].run(percent);
}
deferred.notifyWith(elem, [animation, percent, remaining]);
if (percent < 1 && length) {
return remaining;
} else {
deferred.resolveWith(elem, [animation]);
return false;
}
},
animation = deferred.promise({
elem: elem,
props: jQuery.extend({},
properties),
opts: jQuery.extend(true, {
specialEasing: {}
},
options),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
duration: options.duration,
tweens: [],
createTween: function (prop, end) {
var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
animation.tweens.push(tween);
return tween;
},
stop: function (gotoEnd) {
var index = 0,
// if we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
if (stopped) {
return this;
}
stopped = true;
for (; index < length; index++) {
animation.tweens[index].run(1);
}
// resolve when we played the last frame
// otherwise, reject
if (gotoEnd) {
deferred.resolveWith(elem, [animation, gotoEnd]);
} else {
deferred.rejectWith(elem, [animation, gotoEnd]);
}
return this;
}
}),
props = animation.props;
propFilter(props, animation.opts.specialEasing);
for (; index < length; index++) {
result = animationPrefilters[index].call(animation, elem, props, animation.opts);
if (result) {
return result;
}
}
jQuery.map(props, createTween, animation);
if (jQuery.isFunction(animation.opts.start)) {
animation.opts.start.call(elem, animation);
}
jQuery.fx.timer(
jQuery.extend(tick, {
elem: elem,
anim: animation,
queue: animation.opts.queue
}));
// attach callbacks from options
return animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);
}
When .hide() is called , a jQuery.Deferred() is created that processes the animation tasks.
This is the reason console.log() is called.
If include start option of .hide() can review that .hide() begins before console.log() is called on next line, though does not block the user interface from performing asynchronous tasks.
$("#mybox").hide({
duration:17000,
start:function() {
console.log("start function of .hide()");
}
});
console.log("Previous command has not yet terminated!");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="mybox">mybox</div>
Native Promise implementation
function init() {
function $(id) {
return document.getElementById(id.slice(1))
}
function hide(duration, start) {
element = this;
var height = parseInt(window.getComputedStyle(element)
.getPropertyValue("height"));
console.log("hide() start, height", height);
var promise = new Promise(function(resolve, reject) {
var fx = height / duration;
var start = null;
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
height = height - fx * 20.5;
element.style.height = height + "px";
console.log(height, progress);
if (progress < duration || height > 0) {
window.requestAnimationFrame(step);
} else {
resolve(element);
}
}
window.requestAnimationFrame(step);
});
return promise.then(function(el) {
console.log("hide() end, height", height);
el.innerHTML = "animation complete";
return el
})
}
hide.call($("#mybox"), 17000);
console.log("Previous command has not yet terminated!");
}
window.addEventListener("load", init)
#mybox {
position: relative;
height:200px;
background: blue;
}
<div id="mybox"></div>

How to run javascript function in web browser only when is not proccesing that function

One of my javascript function is processing millions of data and it is called ~1 time every second from a hardware event. Then the web browser is idle in that function processing.
I tried to set a flag for running (or not running) that function:
if (!is_calculating)
is_calculating = true;
else
return;
my_function(); // do heavy stuff
is_calculating = false;
but it's not working, because it is entering into the code and the web browser enter in an idle status until is finishing. When it is returning, the flag is always OK, because it finished the // do heavy stuff
Can I do something for this behavior? I'd like to jump function execution if a flag is set.
The problem is, by default javascript runs in a single thread on browsers, so your code is executing completely before it even begins to process the next call, resulting in is_calculating always being false when the function is called. One workaround you could use (not the cleanest solution in the world), is to divide your monolithic 'heavy stuff' function into a number of smaller functions and have them call each other with setTimeout(nextFunc, 1). Having them call each other that way gives the browser a moment to do what it needs to do, and additionally call your function again if that's what it's doing. This time, because your function is called in the 'middle' of it already being executed, is_calculating is still going to be true, and the call will return at the beginning like you expect it to. Note this solution probably isn't as preferable as the Web Workers solution, but it is simpler.
function sleep(millis) {
var date = new Date()
var curDate = null
do { curDate = new Date() }
while(curDate-date < millis)
}
function reallyLong() {
if(!reallyLong.flag) {
reallyLong.flag = true
} else {
console.log("Not executing")
return
}
sleep(250)
setTimeout(reallyLong2, 1)
function reallyLong2() {
sleep(250)
setTimeout(reallyLong3, 1)
}
function reallyLong3() {
sleep(250)
setTimeout(reallyLong4, 1)
}
function reallyLong4() {
sleep(250)
console.log("executed")
reallyLong.flag = false
}
}
If you define all your consecutive functions inside the primary function, it also allows them all to access the same data simply and easily.
The only catch now is if your function was returning some value, you need to rewrite it to either return a promise (Either of your own design or using a library like Q), or accept a callback as a parameter that the last function in the 'chain' will call with the return value as a parameter.
Note that the sleep function above is a hack, and awful, and terrible, and should never be used.
By default JavaScript execution in browsers is not concurrent. This means, usually there can be only one currently executing piece of code.
You have to use Web Workers API to make you code run concurrently.

Checking if a JavaScript setTimeout has fired

I'd like to be able to dispatch a bunch of work via JavaScript to be done in the browser in such a way that the browser stays responsive throughout.
The approach I'm trying to take is to chunk up the work, passing each chunk to a function that is then queued with a setTimeout(func, 0) call.
I need to know when all the work is done, so I'm storing the returned timer ID in a map (id -> true|false). This mapping is set to false in the next block of code after I have the timer ID, and the queued function sets the mapping to true when it completes... except, of course, the queued function doesn't know its timer ID.
Maybe there's a better/easier way... or some advice on how I can manipulate my map as I need to?
I would queue the work in an array, use one timeout to process the queue and call a callback once the queue is empty. Something like:
var work = [...];
var run = function(work, callback) {
setTimeout(function() {
if(work.length > 0) {
process(work.shift());
setTimeout(arguments.callee, 25);
}
else {
callback();
}
}, 25);
};
run(work, function() {
alert('Work is done!');
});
As JavaScript in browsers is single threaded there is no real advantage to run multiple timeouts (at least I think this is what you are doing). It may even slow down the browser.
I'd like to add that although javascript is single threaded you can still have multiple ajax calls going at once. I recently had a site that needed to do potentially hundreds of ajax calls and the browser just couldn't handle it. I created a queue that used setTimeOut to run 5 calls at once. When one of the ajax calls returned it fired a callback (which is handled by a single thread) and then made the next call on the stack.
Imagine you're a manager that can only talk to one person at a time, you give 5 employees assignments, then wait for their responses, which may come in any order. Once the first employee comes back and gives you the information, you give them a new assignment and wait for the next employee (or perhaps even the same employee) to come back. So although you're "single threaded" 5 things are going on at once.
There is an example right in the HTML Standard, how it is best to handle it:
To run tasks of several milliseconds back to back without any delay,
while still yielding back to the browser to avoid starving the user
interface (and to avoid the browser killing the script for hogging the
CPU), simply queue the next timer before performing work:
function doExpensiveWork() {
var done = false;
// ...
// this part of the function takes up to five milliseconds
// set done to true if we're done
// ...
return done;
}
function rescheduleWork() {
var handle = setTimeout(rescheduleWork, 0); // preschedule next iteration
if (doExpensiveWork())
clearTimeout(handle); // clear the timeout if we don't need it
}
function scheduleWork() {
setTimeout(rescheduleWork, 0);
}
scheduleWork(); // queues a task to do lots of work
The moment of finishing the work is pretty clear, when clearTimeout is called.

Categories

Resources