Stopping current operation and proceed to another (new) operation - javascript

function windowResize() {
someFunction();
console.log("test3");
}
function someFunction(){
console.log("test");
longExecutingFunctionWithAsyncReq();
console.log("test2");
}
function longExecutingFunctionWithAsyncReq() {
// some codes here
}
whenever the window is resize(zoomed out/in), this function is called.
But if the user spams the zoom, someFunction() will not have the time to finish and will then cause the error.
I'm thinking of addressing this issue by stopping the current operation and then process the new operation. Also, I've tried reading about Deferred and Promise, but I can't grasp the simplicity of the topic and I'm not sure if it really solves my problem. Plus, I've also checked on callbacks and was very doubtful that this will not solve my problem either.
If my solution is not possible though, I thought of just queuing the operations, but the downside might be, the queue might overflow if not controlled. As for this solution, I've not looked any farther to this, except reading about it.

you could use a timeout and clear it before resetting it when the resize function is called:
var myTimeout;
function windowResize() {
clearTimeout(myTimeout);
myTimeout = setTimeout(someFunction, 500);
}
this way the function will be called when the user stops resizing and 500 miliseconds have passed.

if you just need to wait for operation to finish you can set up a flag.
var working = false;
function windowResize() {
if (!working){
working = true;
someFunction();
console.log("test3");
}
}
function someFunction(){
console.log("test");
longExecutingFunctionWithAsyncReq();
console.log("test2");
}
function longExecutingFunctionWithAsyncReq() {
// some codes here
// on finish set working to False
}

var isStillWorking = false;
function windowResize() {
if(isStillWorking) {
// Do nothing.
} else {
someFunction(function(){
isStillWorking = false;
});
console.log("test3");
}
}
function someFunction(callback){
isStillWorking = true;
console.log("test");
longExecutingFunctionWithAsyncReq();
console.log("test2");
}
function longExecutingFunctionWithAsyncReq() {
// some codes here
}
To clarify more of Anton's answer I manage to implement the same thing using a flag [global] variable and a callback. I use a callback in order to flag=false since I also need to wait for the asynchronous requests inside the function to finish before resetting the flag.

Related

Javascript - Disable all nested functions for some time after one function function has been executed

After a function has run I want to disable a whole set of functions can be executed again. I thought the most logical way would be to put them all together inside an overarching function (in this case function run) and disable that function for some time.
So for example in the code below, when function exampleOne is executed I want to disable the whole run function for X time before it can run again.
function run(){
function exampleOne(){
// Code
sleep(1000);
}
function exampleTwo(){
// Code
sleep(1000);
}
}
run();
Take a look at underscore.js and especially the throttle or debounce functions.
You can define your functions as variables then you can disable them by assigning an empty or error functions to these variables. Two functions (e.g. enable/disable) can be responsible to disable/enable the whole set of functions. and of course you can use setTimeout to manage the delay.
for example:
var exampleOne, exampleTwo;
function enable(){
exampleOne = function(){
// do something
disable();
setTimeout(function() { enable(); }, 10000);
}
exampleTwo = function(){
// do something
disable();
setTimeout(function() { enable(); }, 10000);
}
}
function disable(){
exampleOne = function(){
Alert("i'm sleep!")
}
exampleTwo = function(){
// do nothing
}
}
enable();

waiting for requestAnimationFrame to finish (via callbacks)

So I'm new here, apologies if this is a basic question but I can't see it answered anywhere else.
I'm trying to write a webapp which shows an animation (using pixijs), and afterwards displays a div requesting a response. My issue is that because the animation is handled using requestAnimationFrame the animation occurs asynchronously, and so the response and animation phases occur simultaneously (the div appears instantly and obscures the animation).
Now I've looked around and the consensus seems to be to use a callback function, which only gets triggered after all the asynchronous work has been performed, allowing that serial progression.
HOWEVER, requestAnimationFrame takes the form
requestAnimationFrame(update_screen_objects),
but breaks when I try to do:
requestAnimationFrame(update_screen_objects(response_phase_callback))
as clearly requestAnimationFrame doesn't like being passed a function that itself has a callback. So my question is: what should I do to the animation loop to ensure that subsequent functions execute AFTER the animation is complete?
Thanks!
EDIT
This is an example of the code in the above form that doesn't work.
function animate(callback) {
var finished = false;
if ((new Date().getTime()) < adaptTime){
runFlicker(false);
} else if ((new Date().getTime()) < judgeTime){
hideAdaptors();
} else if ((new Date().getTime()) > judgeTime){
stage.visible = false;
finished = true;
}
renderer.render(stage);
if (!finished){
requestAnimationFrame( animate(callback) ); //Ensures it will keep looping
//requestAnimationFrame(animate); //This does work, but my issue still persists
} else {
callback(); //By the time callback() is required, you can't access it as requestAnimationFrame doesn't accept animate() with a function passed to it.
}
}
No need for a complex wrapper, just do:
requestAnimationFrame(update_screen_objects.bind(window, response_phase_callback))
This "currys" the update_screen_objects function by partially applying some arguments. The result of .bind(context, arg1) is a function that when called, only takes any arguments that aren't already bound, e.g arg2, arg3, etc.
Try this out. You basically need to generate that step (animate) function with the callback, instead of passing in the results of your call to animate, which would be undefined.
function generateAnimation(callback) {
function step() {
var finished = false;
var now = (new Date()).getTime();
if (now < adaptTime) {
runFlicker(false);
} else if (now < judgeTime) {
hideAdaptors();
} else if (now > judgeTime) {
stage.visible = false;
finished = true;
}
renderer.render(stage);
if (!finished) {
requestAnimationFrame(step);
} else {
callback();
}
}
return step;
}
// Usage:
requestAnimationFrame(generateAnimation(callback));

Execute statement after return statement in Javascript

window.onbeforeunload = function() {
if (document.getElementById("parentpan").style.display == "block") {
return "You are logged out.";
Logout();
}
};
I want the logout() function to be called after the return statement, is it possible?
You can't execute anything after a return statement.
edit: the finally statement allows code execution after a return for cleanup purposes.
(This is a good example for an XY-Question: You are asking about Y while never telling us for what X you actually need it).
The best possible way and most efficient way is try, catch and finally
catch is optional in this
`try{
// do something
return;
} finally {
// call function after return
}`
https://youtu.be/Is_o_L-ZIS8 this is helpful for you
The return statement ends a function, you cannot execute code after it. You could do this:
ret = "You are logged out.";
Logout();
return ret;
What you need is to execute Logout asynchronously. This can be easily achieve in JavaScript by using the setTimeout function as others have said. Here's a method I commonly use to call functions asynchronously:
Function.prototype.async = function () {
setTimeout.bind(null, this, 0).apply(null, arguments);
};
This method pushes a function call onto the event loop immediately (after 0 ms). Hence the function is executed after the current code completes (which for you is after you return). Here's a simple example of how to use it:
alert.async("This will be displayed later.");
alert("This will be displayed first.");
Since the first alert is called asynchronously it will execute after the second call to alert. As simple as preceding your function call with async. This is what you would do in your case:
window.onbeforeunload = function () {
if (document.getElementById("parentpan").style.display === "block") {
Logout.async();
return "You are logged out.";
}
};
What's the disadvantage? Since the function is blocked on the event loop it may never get the chance to execute (hence the user will never logout). Such a situation may arise. It usually occurs when the control goes into an infinite loop, or hangs because of a blocking AJAX request.
Good news for you however, this happens on a very rare occasion. So don't worry about it. Just use setTimeout like everyone else is bantering you to and you'll do just fine. Personally I think you should log out before returning a message that "You are logged out.", but it's your application.
Happy New Year. Cheers!
In general if you want something to be executed after the function has returned, you can set a timer:
function myFunction() {
if (document.getElementById("parentpan").style.display == "block") {
setTimeout(Logout, 50); // Logout will be called 50ms later
return "You are logged out.";
}
};
However, as noted in comments, this is not a good idea for onbeforeunload, as the timer event will not be fired if the page finished unloading first.
Most of the other answerers are missing what you are trying to do here. You want window.onbeforeunload to act like window.confirm(). There is no way to act on the ok action in the onbeforeunload event.
What you would have to do is hook it up on onunload to do the action.
window.onbeforeunload = function () {
return "Your session will be logged out"
};
window.onunload = function () {
logout();
}
Problem with this is modern day browsers will kill a lot of processes that run in unload/beforeunload to "speed up" the browser so it is faster. So if it is asynchronous, you will have a race condition.
return means you are returning from the execution of the called function.When return statement is executed, system understands that the function execution is over and it will switch to the main program from which the function is called.
In the program, you can see a statement after return.But the system wont check that even.
If you have jquery in your project you can use defered mechanism. You can return promise object for ongoing tasks like this :
function task() {
var defered = $.Deferred();
setTimeout(defered.resolve , 5000);
return defered.promise();
}
function task2() {
var defered = $.Deferred();
setTimeout(defered.resolve , 10000);
return defered.promise();
}
function run() {
return $.when(task(),task2());
}
var promise = run();
promise.done(function(){
alert("All tasks has been completed");
});
Demo
You can use setTimeout to achieve this. Your code should be as below
window.onbeforeunload = function() {
if (document.getElementById("parentpan").style.display == "block") {
setTimeout(function(){
Logout();
}, 0);
return "You are logged out.";
}
};
This will make sure that Logout is executed after return statement.
var a = 10;
function b(){
a = 25;
return;
function a(){}
}
b();
document.write(a);
try it
I found two ways to approach this.
The first one is as stated above by Bhavsar Japan
1. Example with try, catch and finally
const example1 = () => {
try {
return console.log('will execute first')
} finally{
console.log('will execute second')
}
return 'will never execute'
}
const main = () => {
const message = example1();
console.log(message)
}
main()
2. Example with Promise.resolve
const example2 = () => {
Promise.resolve()
.then(() => console.log('will execute after return'));
return 'will execute first'
}
const main = () => {
const message = example2();
console.log(message);
}
main();
I just written a way to return a result and then call a callback, like this:
function after_return(result, callback) {
function returner(resolve) {
if (!resolve) {
new Promise((res) => returner(res)).then(callback);
return result;
} else {
resolve();
}
}
return returner(undefined);
}
function main(a, b) {
return after_return(a + b, (_) => {
console.log("DONE");
});
}
console.log(main(5, 4));
I'm guessing that Logout is a time-intensive process and you want to provide feedback to the user before executing it:
setTimeout(Logout,1);
return "You are logged out.";

Javascript click and hold on element using setTimeout

I need to have some functionality in my web app where a specific action occurs when the user clicks and holds on an element. Think of it like the long press on Android.
I have my div:
<div id="myDiv"
onmousedown="press()"
onmouseup="cancel()"
onmouseout="cancel()"
onmousemove="cancel()">Long Click Me</div>
and my javascript:
var down = false;
function press()
{
down = true;
setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false; // this doesn't happen when user moves off div while holding mouse down!
}
function action()
{
if (!down)
return; // if the flag is FALSE then do nothing.
alert("Success!");
down = false;
}
This works as long as all I do is press and hold on the element. I have the onmouseout and onmousemove events to call cancel() because I want the user to have the option to change their mind and move the mouse off the element before action() starts.
Unfortunately, it seems that my code does not do this.
In fact, if the use clicks down for a moment, moves the mouse off the div and releases before the 1.5 sec then action() won't bail out as expected.
Edit: Thanks for your input everyone but it turns out I'm just a little bit special and didn't see that I forgot a capital letter in my HTML in my onmouseout. The sample code I gave above should work exactly as expected.
Of course action() is still called. You didn't actually cancel the setTimeout() function. I would suspect that maybe in your real code, you have a scoping issue and maybe aren't testing the same version of the done variable that you think you are.
A better way than using the down flag would be to keep track of the return value from setTimeout() and actually cancel the timer in the cancel() function. Then, action() will never fire when you don't want it to. I think it's also technically a more correct behavior when you mouseout to cancel any chance of the timer firing.
Also, there is no such thing as:
bool down = false;
in javascript. It would have to be:
var down = false;
I would recommend this code:
var downTimer = null;
function down()
{
cancel();
downTimer = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
if (downTimer)
{
clearTimeout(downTimer);
downTimer = null;
}
}
function action()
{
downTimer = null;
alert("Success!");
}
You also need to clear the timeout in your cancel function - otherwise it will still fire - as you initiated it in the down function.
so..
bool down = false;
//your timeout var
var t;
function down()
{
down = true;
t = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false;
clearTimeout(t);
}
function action()
{
if (!down)
return;
alert("Success!");
down = false;
}
There are several things wrong with your code as I see it.
First
bool down = false;
is not valid JavaScript. It should be
var down = false;
Then you have two variables called down: the boolean value and the function. The function will overwrite the variable, until as such time that you execute one of the statements that sets down to true or false.
As others have said: once set, the deferred function will continue to be executed 1.5 seconds later, unless you cancel the timeout. But then again it doesn't matter, since you do check to see if the mouse button is down before doing anything.
So I'd say rename the boolean variable to isMouseDown or something and try again.
to cancel the timeout in the cancel() function, use
var mytimer = null;
function ondown(){mytimer = setTimeOut('action()', 1500;)}
function cancel(){clearTimeout(mytimer);}
function action(){mytimer=null; alert('success!');}
also note that you used down first as a variable end then as a function... Calling if(!down) will always return false because down refers to a function.

determining the end of asynchronous operations javascript

If I have a function that's passed this function:
function(work) {
work(10);
work(20);
work(30);
}
(There can be any number of work calls with any number in them.)
work performance some asynchronous activity—say, for this example, it just is a timeout. I have full control over what work does on the completion of this operation (and, in fact, its definition in general).
What's the best way of determining when all the calls to work are done?
My current method increments a counter when work is called and decrements it when it completes, and fires the all work done event when the counter is 0 (this is checked after every decrement). However, I worry that this could be a race condition of some sort. If that is not the case, do show my why and that would be a great answer.
There are a ton of ways you can write this program, but your simple technique of using a counter will work just fine.
The important thing to remember, the reason this will work, is because Javascript executes in a single thread. This is true of all browsers and node.js AFAIK.
Based on the thoughtful comments below, the solution works because the JS event loop will execute the functions in an order like:
function(work)
work(10)
counter++
Start async function
work(20)
counter++
Start async function
work(30)
counter++
Start async function
-- back out to event loop --
Async function completes
counter--
-- back out to event loop --
Async function completes
counter--
-- back out to event loop --
Async function completes
counter--
Counter is 0, so you fire your work done message
-- back out to event loop --
There's no race condition. There is the added requirement for every request made to perform a decrement when it's finished (always! including on http failure, which is easy to forget). But that can be handled in a more encapsulated way by wrapping you calls.
Untested, but this is the gist (I've implemented an object instead of a counter, so theoretically you can extend this to have more granular queries about specific requests):
var ajaxWrapper = (function() {
var id = 0, calls = {};
return {
makeRequest: function() {
$.post.apply($, arguments); // for example
calls[id] = true;
return id++;
},
finishRequest: function(id) {
delete calls[id];
},
isAllDone: function(){
var prop;
for(prop in calls) {
if(calls.hasOwnProperty(prop)) {return false;}
}
return true;
}
};
})();
Usage:
Instead of $.post("url", ... function(){ /*success*/ } ... ); We'll do
var requestId;
requestId = ajaxWrapper.makeRequest("url", ...
function(){ /*success*/ ajaxWrapper.finishRequest(requestId); } ... );
If you wanted to be even more sophisticated you could add the calls to finishRequest yourself inside the wrapper, so usage would be almost entirely transparent:
ajaxWrapper.makeRequest("url", ... function(){ /*success*/ } ... );
I have an after utility function.
var after = function _after(count, f) {
var c = 0, results = [];
return function _callback() {
switch (arguments.length) {
case 0: results.push(null); break;
case 1: results.push(arguments[0]); break;
default: results.push(Array.prototype.slice.call(arguments)); break;
}
if (++c === count) {
f.apply(this, results);
}
};
};
The following code below would just work. Because javascript is single threaded.
function doWork(work) {
work(10);
work(20);
work(30);
}
WorkHandler(doWork);
function WorkHandler(cb) {
var counter = 0,
finish;
cb(function _work(item) {
counter++;
// somethingAsync calls `finish` when it's finished
somethingAsync(item, function _cb() {
finish()
});
});
finish = after(counter, function() {
console.log('work finished');
});
};
I guess I should explain.
We pass the function that does work to the workhandler.
The work handler calls it and passes in work.
The function that does work calls work multiple times incrementing the counter
Since the function that does work is not asynchronous (very important) we can define the finish function after it has finished.
The asynchronouswork that is being done cannot finish (and call the undefined finish function) before the current synchronous block of work (the execution of the entire workhandler) has finished.
This means that after the entire workhandler has finished (and the variable finish is set) the asynchronous work jobs will start to end and call finish. Only once all of them have called finish will the callback send to after fire.

Categories