Run While loop in the background - javascript

i have a javascript application Angular based that runs a while loop after a user press a button it runs the loop until we get a certain number then the loop ends. currently am not able to do anything else on the UI when the loop is running is there a way to push this loop to the background so the user can continue other things on the UI.

Use angular watchers for that:
$rootscope.watch(myParam, function () {});
Or use non-blocking setInterval():
var timer = setInterval(function () {
if (myParam == 'what-i-need') {
clearInterval(timer);
}
}, 200);

You can use webworker, as sample code below (the code is not fully functional but it just to give you an idea.
(
function () {
var scope = self;
var condition = false
scope.addEventListener('message', function (event) {
var caller = event.data;
if(caller.name && caller.command && caller.command === 'TERMINATE'){
return;
}
start(caller);
}, false);
function start(){
while (condition) {
if(condition)
scope.postMessage({result:"result"});
}
}
})();
In your angularjs controller or service
if (!worker) {
worker = new $window.Worker("./online-capability-worker.js");
worker.addEventListener('message', onResponse, false);
}
function onResponse(event) {
var response = event.data;
//This is my nuber returned by worker
}

Javascript is synchronous, while event driven systems allow it to mimic an asynchronous language, your code is still running on a single thread. You could use a setTimeout to recursively call a function rather than use the while loop, that way there is time for the thread to do other things in between each iteration.
function incrementNumber(initial, destination){
if(initial < destination){
setTimeout(function(){incrementNumber(initial+1, destination}), 10);
}else{
alert('We found the number!');
}
}
I would like to point out that I agree with the use of setInterval for something as simple as changing a number, but in browsers (to the best of my knowledge still), the interval is kicked off from the time the callback is initially called, which can cause unexpected results if the callback itself has any significant execution time (say, an ajax call).

Related

How do I add a delay between each iteration of a for of or forEach loop over Set elements?

I have a function like shown below where websocketServer.clients basically contains a Set of websocket objects. The setInterval causes my server to get spikes and I would like to basically terminate inactive clients one by one with a small delay in between in a more uniform manner. Both forEach and for of loops run instantaneously, how do I add a delay between them to replicate the same functionality without using a setInterval?
export function terminateIdleConnections() {
const interval = setInterval(function ping() {
console.log('entry', new Date());
websocketServer.clients.forEach(function each(ws) {
// #ts-ignore
if (ws.isAlive === false) {
console.log('terminating connection', new Date());
return ws.terminate();
} else {
console.log('pinging connection', new Date());
// #ts-ignore
ws.isAlive = false;
ws.ping();
}
});
}, WEBSOCKET_CHECK_IDLE_CONNECTION_FREQUENCY);
websocketServer.on('close', function close() {
console.log('terminating INTERVAL', new Date());
clearInterval(interval);
});
}
I suppose that's a weird approach, but what if you try to implement this with setTimeout? You'd need to initiate another setTimeout with each function call, so the next function activity is rescheduled.
Unluckily I have no setup available to try this approach.
setInterval and setTimeout are the only JavaScript approaches I know to delay code execution. Afaik every alternative implementation runs back to these functions, or burns cpu time by looping until a certain date/time is reached.

Global variable value not reflecting in loop

My function OAuth.getSessionInfo returns response still why does the loop goes infinite?
var resp = false;
OAuth.getSessionInfo(function(data) {
resp = true;
})
do {
console.log("waiting............")
} while (!resp);
PS: Please suggest good title for the question.. I am confused on what should be the title for question
Lets remind what multi-threading and concurrency means:
Multi-threading - doing multiple things simultaneously.
Concurrency - switching fast between multiple things, thus emulating them being done simultaneously.
Javascript neither supports the first technique nor the second one. Instead it executes block of code till the end, and then executes next block that was scheduled with setTimeout or setInterval or one that came from event handler (e.g. onclick, onload).
Now if you look at your code you can see that it can't be completed without inner function being completed, but that inner function won't be executed until the outer one completes. And that's why your application hangs. You can also try next code which demonstrates your issue:
setTimeout(function() {
x = false;
console.log("won't be invoked");
}, 0);
var x = true;
while(x) {
console.log('looping');
}
P.S. This javascript's specifics is also the reason why there is no sleep function available - it simply doesn't make any sense to stop the only code executor you have.
You are getting an infinite loop because your while loop keeps running because it doesn't have a point to stop at. The way you have it now it says do this while true. So it keeps running.
Once the loop is started, you haven't updated the value of resp. Try the following:
var resp = false;
do {
OAuth.getSessionInfo(function(data) {
if (data.sessionActive == true) {
resp = true;
} else {
resp = false;
}
});
console.log("waiting............")
} while (!resp);

Using $.ajaxStop() to determine when page is finished loading in CasperJS

So far in my tests written in CasperJS, I've been using waitForSelector() on page-specific elements to determine if a page has fully loaded (including all the async ajax requests). I was hoping to come up with a more standard way of waiting for page load and was wondering if the following was possible?
Inject as clientscript the following (include.js)
$(document).ajaxStop(function() {
// Do something
})
Description of ajaxStop according to jquery api: Register a handler to be called when all Ajax requests have completed.
Define a casper.waitForLoad function that when called would wait for the "something" in above code block
Use the function in several parts of the test.
Also any tips on the // Do Something part would also be appreciated :) I was thinking about using the window.callPhantom feature in phantomJS but I'm reading that it's not officially supported in casperjs.
I would do something like this in include.js:
(function(){
window._allAjaxRequestsHaveStopped = false;
var interval;
$(document).ajaxStop(function() {
if (interval) {
clearInterval(interval);
interval = null;
}
interval = setTimeout(function(){
window._allAjaxRequestsHaveStopped = true;
}, 500);
});
$(document).ajaxStart(function() {
window._allAjaxRequestsHaveStopped = false;
if (interval) {
clearInterval(interval);
interval = null;
}
});
})();
This sets a (hopefully unique) variable to the window object that can be later retrieved. This also waits a little longer incase there is another request after the previous batch ended.
In CasperJS you would probably do something like the following to wait for the change in the request status. This uses adds a new function to the casper object and uses casper.waitFor() internally to check the change.
casper.waitForAjaxStop = function(then, onTimeout, timeout){
return this.waitFor(function(){
return this.evaluate(function(){
return window._allAjaxRequestsHaveStopped;
});
}, then, onTimeout, timeout);
};
And use it like this:
casper.start(url).waitForAjaxStop().then(function(){
// do something
}).run();
or this:
casper.start(url).thenClick(selector).waitForAjaxStop().then(function(){
// do something
}).run();

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.

Javascript - how to avoid blocking the browser while doing heavy work?

I have such a function in my JS script:
function heavyWork(){
for (i=0; i<300; i++){
doSomethingHeavy(i);
}
}
Maybe "doSomethingHeavy" is ok by itself, but repeating it 300 times causes the browser window to be stuck for a non-negligible time. In Chrome it's not that big of a problem because only one Tab is effected; but for Firefox its a complete disaster.
Is there any way to tell the browser/JS to "take it easy" and not block everything between calls to doSomethingHeavy?
You could nest your calls inside a setTimeout call:
for(...) {
setTimeout(function(i) {
return function() { doSomethingHeavy(i); }
}(i), 0);
}
This queues up calls to doSomethingHeavy for immediate execution, but other JavaScript operations can be wedged in between them.
A better solution is to actually have the browser spawn a new non-blocking process via Web Workers, but that's HTML5-specific.
EDIT:
Using setTimeout(fn, 0) actually takes much longer than zero milliseconds -- Firefox, for example, enforces a minimum 4-millisecond wait time. A better approach might be to use setZeroTimeout, which prefers postMessage for instantaneous, interrupt-able function invocation, but use setTimeout as a fallback for older browsers.
You can try wrapping each function call in a setTimeout, with a timeout of 0. This will push the calls to the bottom of the stack, and should let the browser rest between each one.
function heavyWork(){
for (i=0; i<300; i++){
setTimeout(function(){
doSomethingHeavy(i);
}, 0);
}
}
EDIT: I just realized this won't work. The i value will be the same for each loop iteration, you need to make a closure.
function heavyWork(){
for (i=0; i<300; i++){
setTimeout((function(x){
return function(){
doSomethingHeavy(x);
};
})(i), 0);
}
}
You need to use Web Workers
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
There are a lot of links on web workers if you search around on google
We need to release control to the browser every so often to avoid monopolizing the browser's attention.
One way to release control is to use a setTimeout, which schedules a "callback" to be called at some period of time. For example:
var f1 = function() {
document.body.appendChild(document.createTextNode("Hello"));
setTimeout(f2, 1000);
};
var f2 = function() {
document.body.appendChild(document.createTextNode("World"));
};
Calling f1 here will add the word hello to your document, schedule a pending computation, and then release control to the browser. Eventually, f2 will be called.
Note that it's not enough to sprinkle setTimeout indiscriminately throughout your program as if it were magic pixie dust: you really need to encapsulate the rest of the computation in the callback. Typically, the setTimeout will be the last thing in a function, with the rest of the computation stuffed into the callback.
For your particular case, the code needs to be transformed carefully to something like this:
var heavyWork = function(i, onSuccess) {
if (i < 300) {
var restOfComputation = function() {
return heavyWork(i+1, onSuccess);
}
return doSomethingHeavy(i, restOfComputation);
} else {
onSuccess();
}
};
var restOfComputation = function(i, callback) {
// ... do some work, followed by:
setTimeout(callback, 0);
};
which will release control to the browser on every restOfComputation.
As another concrete example of this, see: How can I queue a series of sound HTML5 <audio> sound clips to play in sequence?
Advanced JavaScript programmers need to know how to do this program transformation or else they hit the problems that you're encountering. You'll find that if you use this technique, you'll have to write your programs in a peculiar style, where each function that can release control takes in a callback function. The technical term for this style is "continuation passing style" or "asynchronous style".
You can make many things:
optimize the loops - if the heavy works has something to do with DOM access see this answer
if the function is working with some kind of raw data use typed arrays MSDN MDN
the method with setTimeout() is called eteration. Very usefull.
the function seems to be very straight forward typicall for non-functional programming languages. JavaScript gains advantage of callbacks SO question.
one new feature is web workers MDN MSDN wikipedia.
the last thing ( maybe ) is to combine all the methods - with the traditional way the function is using only one thread. If you can use the web workers, you can divide the work between several. This should minimize the time needed to finish the task.
I see two ways:
a) You are allowed to use Html5 feature. Then you may consider to use a worker thread.
b) You split this task and queue a message which just do one call at once and iterating as long there is something to do.
There was a person that wrote a specific backgroundtask javascript library to do such heavy work.. you might check it out at this question here:
Execute Background Task In Javascript
Haven't used that for myself, just used the also mentioned thread usage.
function doSomethingHeavy(param){
if (param && param%100==0)
alert(param);
}
(function heavyWork(){
for (var i=0; i<=300; i++){
window.setTimeout(
(function(i){ return function(){doSomethingHeavy(i)}; })(i)
,0);
}
}())
There is a feature called requestIdleCallback (pretty recently adopted by most larger platforms) where you can run a function that will only execute when no other function takes up the event loop, which means for less important heavy work you can execute it safely without ever impacting the main thread (given that the task takes less than 16ms, which is one frame. Otherwise work has to be batched)
I wrote a function to execute a list of actions without impacting main thread. You can also pass a shouldCancel callback to cancel the workflow at any time. It will fallback to setTimeout:
export const idleWork = async (
actions: (() => void)[],
shouldCancel: () => boolean
): Promise<boolean> => {
const actionsCopied = [...actions];
const isRequestIdleCallbackAvailable = "requestIdleCallback" in window;
const promise = new Promise<boolean>((resolve) => {
if (isRequestIdleCallbackAvailable) {
const doWork: IdleRequestCallback = (deadline) => {
while (deadline.timeRemaining() > 0 && actionsCopied.length > 0) {
actionsCopied.shift()?.();
}
if (shouldCancel()) {
resolve(false);
}
if (actionsCopied.length > 0) {
window.requestIdleCallback(doWork, { timeout: 150 });
} else {
resolve(true);
}
};
window.requestIdleCallback(doWork, { timeout: 200 });
} else {
const doWork = () => {
actionsCopied.shift()?.();
if (shouldCancel()) {
resolve(false);
}
if (actionsCopied.length !== 0) {
setTimeout(doWork);
} else {
resolve(true);
}
};
setTimeout(doWork);
}
});
const isSuccessful = await promise;
return isSuccessful;
};
The above will execute a list of functions. The list can be extremely long and expensive, but as long as every individual task is under 16ms it will not impact main thread. Warning because not all browsers supports this yet, but webkit does

Categories

Resources