I've only found rather complicated answers involving classes, event handlers and callbacks (which seem to me to be a somewhat sledgehammer approach). I think callbacks may be useful but I cant seem to apply these in the simplest context. See this example:
<html>
<head>
<script type="text/javascript">
function myfunction() {
longfunctionfirst();
shortfunctionsecond();
}
function longfunctionfirst() {
setTimeout('alert("first function finished");',3000);
}
function shortfunctionsecond() {
setTimeout('alert("second function finished");',200);
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
In this, the second function completes before the first function; what is the simplest way (or is there one?) to force the second function to delay execution until the first function is complete?
---Edit---
So that was a rubbish example but thanks to David Hedlund I see with this new example that it is indeed synchronous (along with crashing my browser in the test process!):
<html>
<head>
<script type="text/javascript">
function myfunction() {
longfunctionfirst();
shortfunctionsecond();
}
function longfunctionfirst() {
var j = 10000;
for (var i=0; i<j; i++) {
document.body.innerHTML += i;
}
alert("first function finished");
}
function shortfunctionsecond() {
var j = 10;
for (var i=0; i<j; i++) {
document.body.innerHTML += i;
}
alert("second function finished");
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
As my ACTUAL issue was with jQuery and IE I will have to post a separate question about that if I can't get anywhere myself!
This question is related to
javascript
asynchronous
callback
execution
synchronous
I had the same problem, this is my solution:
var functionsToCall = new Array();_x000D_
_x000D_
function f1() {_x000D_
$.ajax({_x000D_
type:"POST",_x000D_
url: "/some/url",_x000D_
success: function(data) {_x000D_
doSomethingWith(data);_x000D_
//When done, call the next function.._x000D_
callAFunction("parameter");_x000D_
}_x000D_
});_x000D_
}_x000D_
_x000D_
function f2() {_x000D_
/*...*/_x000D_
callAFunction("parameter2");_x000D_
}_x000D_
function f3() {_x000D_
/*...*/_x000D_
callAFunction("parameter3");_x000D_
}_x000D_
function f4() {_x000D_
/*...*/_x000D_
callAFunction("parameter4");_x000D_
}_x000D_
function f5() {_x000D_
/*...*/_x000D_
callAFunction("parameter5");_x000D_
}_x000D_
function f6() {_x000D_
/*...*/_x000D_
callAFunction("parameter6");_x000D_
}_x000D_
function f7() {_x000D_
/*...*/_x000D_
callAFunction("parameter7");_x000D_
}_x000D_
function f8() {_x000D_
/*...*/_x000D_
callAFunction("parameter8");_x000D_
}_x000D_
function f9() {_x000D_
/*...*/_x000D_
callAFunction("parameter9");_x000D_
}_x000D_
_x000D_
function callAllFunctionsSy(params) {_x000D_
functionsToCall.push(f1);_x000D_
functionsToCall.push(f2);_x000D_
functionsToCall.push(f3);_x000D_
functionsToCall.push(f4);_x000D_
functionsToCall.push(f5);_x000D_
functionsToCall.push(f6);_x000D_
functionsToCall.push(f7);_x000D_
functionsToCall.push(f8);_x000D_
functionsToCall.push(f9);_x000D_
functionsToCall.reverse();_x000D_
callAFunction(params);_x000D_
}_x000D_
_x000D_
function callAFunction(params) {_x000D_
if (functionsToCall.length > 0) {_x000D_
var f=functionsToCall.pop();_x000D_
f(params);_x000D_
}_x000D_
}
_x000D_
Put your code in a string, iterate, eval, setTimeout and recursion to continue with the remaining lines. No doubt I'll refine this or just throw it out if it doesn't hit the mark. My intention is to use it to simulate really, really basic user testing.
The recursion and setTimeout make it sequential.
Thoughts?
var line_pos = 0;
var string =`
console.log('123');
console.log('line pos is '+ line_pos);
SLEEP
console.log('waited');
console.log('line pos is '+ line_pos);
SLEEP
SLEEP
console.log('Did i finish?');
`;
var lines = string.split("\n");
var r = function(line_pos){
for (i = p; i < lines.length; i++) {
if(lines[i] == 'SLEEP'){
setTimeout(function(){r(line_pos+1)},1500);
return;
}
eval (lines[line_pos]);
}
console.log('COMPLETED READING LINES');
return;
}
console.log('STARTED READING LINES');
r.call(this,line_pos);
OUTPUT
STARTED READING LINES
123
124
1 p is 0
undefined
waited
p is 5
125
Did i finish?
COMPLETED READING LINES
I am an old hand at programming and came back recently to my old passion and am struggling to fit in this Object oriented, event driven bright new world and while i see the advantages of the non sequential behavior of Javascript there are time where it really get in the way of simplicity and reusability. A simple example I have worked on was to take a photo (Mobile phone programmed in javascript, HTML, phonegap, ...), resize it and upload it on a web site. The ideal sequence is :
All this would be a very simple sequential program if we would have each step returning control to the next one when it is finished, but in reality :
And btw 4 of the 5 steps involve callback functions.
My solution thus is to nest each step in the previous one and use .onload and other similar stratagems, It look something like this :
takeAPhoto(takeaphotocallback(photo) {
photo.onload = function () {
resizePhoto(photo, resizePhotoCallback(photo) {
uploadPhoto(photo, uploadPhotoCallback(status) {
informUserOnOutcome();
});
});
};
loadPhoto(photo);
});
(I hope I did not make too many mistakes bringing the code to it's essential the real thing is just too distracting)
This is I believe a perfect example where async is no good and sync is good, because contrary to Ui event handling we must have each step finish before the next is executed, but the code is a Russian doll construction, it is confusing and unreadable, the code reusability is difficult to achieve because of all the nesting it is simply difficult to bring to the inner function all the parameters needed without passing them to each container in turn or using evil global variables, and I would have loved that the result of all this code would give me a return code, but the first container will be finished well before the return code will be available.
Now to go back to Tom initial question, what would be the smart, easy to read, easy to reuse solution to what would have been a very simple program 15 years ago using let say C and a dumb electronic board ?
The requirement is in fact so simple that I have the impression that I must be missing a fundamental understanding of Javsascript and modern programming, Surely technology is meant to fuel productivity right ?.
Thanks for your patience
Raymond the Dinosaur ;-)
In your example, the first function does actually complete before the second function is started. setTimeout does not hold execution of the function until the timeout is reached, it will simply start a timer in the background and execute your alert statement after the specified time.
There is no native way of doing a "sleep" in JavaScript. You could write a loop that checks for the time, but that will put a lot of strain on the client. You could also do the Synchronous AJAX call, as emacsian described, but that will put extra load on your server. Your best bet is really to avoid this, which should be simple enough for most cases once you understand how setTimeout works.
If you don't insist on using pure Javascript, you can build a sequential code in Livescript and it looks pretty good. You might want to take a look at this example:
# application
do
i = 3
console.log td!, "start"
<- :lo(op) ->
console.log td!, "hi #{i}"
i--
<- wait-for \something
if i is 0
return op! # break
lo(op)
<- sleep 1500ms
<- :lo(op) ->
console.log td!, "hello #{i}"
i++
if i is 3
return op! # break
<- sleep 1000ms
lo(op)
<- sleep 0
console.log td!, "heyy"
do
a = 8
<- :lo(op) ->
console.log td!, "this runs in parallel!", a
a--
go \something
if a is 0
return op! # break
<- sleep 500ms
lo(op)
Output:
0ms : start
2ms : hi 3
3ms : this runs in parallel! 8
3ms : hi 2
505ms : this runs in parallel! 7
505ms : hi 1
1007ms : this runs in parallel! 6
1508ms : this runs in parallel! 5
2009ms : this runs in parallel! 4
2509ms : hello 0
2509ms : this runs in parallel! 3
3010ms : this runs in parallel! 2
3509ms : hello 1
3510ms : this runs in parallel! 1
4511ms : hello 2
4511ms : heyy
Another way to look at this is to daisy chain from one function to another. Have an array of functions that is global to all your called functions, say:
arrf: [ f_final
,f
,another_f
,f_again ],
Then setup an array of integers to the particular 'f''s you want to run, e.g
var runorder = [1,3,2,0];
Then call an initial function with 'runorder' as a parameter, e.g. f_start(runorder);
Then at the end of each function, just pop the index to the next 'f' to execute off the runorder array and execute it, still passing 'runorder' as a parameter but with the array reduced by one.
var nextf = runorder.shift();
arrf[nextf].call(runorder);
Obviously this terminates in a function, say at index 0, that does not chain onto another function. This is completely deterministic, avoiding 'timers'.
I tried the callback way and could not get this to work, what you have to understand is that values are still atomic even though execution is not. For example:
alert('1');
<--- these two functions will be executed at the same time
alert('2');
<--- these two functions will be executed at the same time
but doing like this will force us to know the order of execution:
loop=2;
total=0;
for(i=0;i<loop;i++) {
total+=1;
if(total == loop)
alert('2');
else
alert('1');
}
In javascript, there is no way, to make the code wait. I've had this problem and the way I did it was do a synchronous SJAX call to the server, and the server actually executes sleep or does some activity before returning and the whole time, the js waits.
Eg of Sync AJAX: http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX
I am back to this questions after all this time because it took me that long to find what I think is a clean solution : The only way to force a javascript sequential execution that I know of is to use promises. There are exhaustive explications of promises at : Promises/A and Promises/A+
The only library implementing promises I know is jquery so here is how I would solve the question using jquery promises :
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function myfunction()
{
promise = longfunctionfirst().then(shortfunctionsecond);
}
function longfunctionfirst()
{
d = new $.Deferred();
setTimeout('alert("first function finished");d.resolve()',3000);
return d.promise()
}
function shortfunctionsecond()
{
d = new $.Deferred();
setTimeout('alert("second function finished");d.resolve()',200);
return d.promise()
}
</script>
</head>
<body>
<a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>
By implementing a promise and chaining the functions with .then() you ensure that the second function will be executed only after the first one has executed It is the command d.resolve() in longfunctionfirst() that give the signal to start the next function.
Technically the shortfunctionsecond() does not need to create a deferred and return a promise, but I fell in love with promises and tend to implement everything with promises, sorry.
Source: Stackoverflow.com