I am trying to make a series of synchronous calls into asynchronous, and I'm using when...done... I'm new at this stuff, but from all the reading I've been doing on this subject the last two days, my code below should work. Well, it does work, but not exactly in the way that I meant for it.
In my test code below I make five calls, and each one would take a different amount of time (in my example, it's based on the length of the string... 1/2 a second per character). My expectation was that the calls that took less time (i.e. the shorter length strings in my example) would complete first I fire off all five calls quickly, and would expect the results to be displayed in order of shorter execution to longer execution.
Here's my code:
var cars = ["Saab", "Chrysler", "Volvo", "BMW", "GT"];
loopAll(cars);
document.getElementById("demo").innerHTML += "Start!<br>";
function loopAll(array) {
for (var i in array) {
$.when( encapsulate(array[i]) ).done( printIt );
}
function encapsulate(name){
var a = $.Deferred();
setTimeout(function(){pause(name.length*500);a.resolve(name);}, 0);
return a;
}
}
function printIt(name){
document.getElementById("demo").innerHTML += name + "<br>";
}
function pause(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}
Each of the elements in the array get printed, and I can see them popping on the display one by one. However, they seem to be synchronous in that they are being displayed in the original order of the array, and the pause is occurring between each of the displayed elements. However, my expectation was that the shorter executing functions finishing (and displaying) sooner than the longer ones.
Note: I am NOT trying to sort the array. My intent is to fire off multiple calls and let the shorter executing ones finish first, and not sequentially. I'm using the array of strings only as an example.
The timeout block isn't really doing anything in this scenario. It will immediately execute its function block.
JavaScript is single threaded, by using that homebrewed 'pause' method you are effectively blocking the thread and causing each loop to be executed synchronously.
If you have some synchronous code, and an asynchronous alternative isn't available, you may be able to use web workers to shift them off of the main thread.
http://www.html5rocks.com/en/tutorials/workers/basics/
In my test code below I make five calls, and each one would take a
different amount of time (in my example, it's based on the length of
the string... 1/2 a second per character).
At
setTimeout(function(){pause(name.length*500);a.resolve(name);}, 0);
the duration appear to be set to 0 for each $.Deferred() object created ? Not certain about expected result of pause ?
My expectation was that the calls that took less time (i.e. the
shorter length strings in my example) would complete first I fire off
all five calls quickly, and would expect the results to be displayed
in order of shorter execution to longer execution.
try setting duration of setTimeout to name.length*500
var cars = ["Saab", "Chrysler", "Volvo", "BMW", "GT"];
loopAll(cars);
document.getElementById("demo").innerHTML += "Start!<br>";
function loopAll(array) {
for (var i in array) {
$.when( encapsulate(array[i]) ).done( printIt );
}
function encapsulate(name){
var a = $.Deferred();
setTimeout(function(){a.resolve(name);}, name.length*500);
return a;
}
}
function printIt(name){
document.getElementById("demo").innerHTML += name + "<br>";
}
// function pause(ms) {
// ms += new Date().getTime();
// while (new Date() < ms){}
// }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="demo"></div>
The code you listed is a bit of a red herring; the problem, it turns out, is in the statement "I am trying to make a series of synchronous calls into asynchronous." In most JavaScript environments, this simply isn't possible.
JS environments are generally single threaded, so even if you use setTimeout to schedule code execution for some time in the future, that code will still block the thread. See this JSFiddle for an example: http://jsfiddle.net/BinaryMuse/r4ct92c5/
Unless you use something like Web Workers (in the browser) or external processes, fibers, or native addons in Node, you can't execute JS code asynchronously.
Related
I'd like to ask wether there is a way to evaluate javascript terms multiple times without needing to parse a term over and over and over again.
Say, you want to evaluate
var1/var2+Math.sqrt(var3)
20 times a second.
This could be problematic when using
ScriptEngine.eval(string)
continueously, because you would have to replace "var1" every single time, then parse it and then let the script engine figure out the order of operations you want to perform.
Is there any alternative way?
Say, you have a configuration file in which a user gets to specify variables which increase and decrease after certain events.
You have a fixed term which javascript needs to process and the user also gets to define, but the variables change.
So is there a way to save a term as a list of operations (which internally speaking, it is) into which you only need to input the variables?
So basically, is there a way around parsing and creating an operation order over and over?
You could evaluate the expression wrapped in a function:
var expression = "var1/var2+Math.sqrt(var3)";
eval( 'function myTest(var1,var2,var3){ return ' + expression + "}" );
console.log(myTest, myTest(1, 2, 9) );
I think you are looking for a for loop.
var x = //number of time you want to run
for (i = 0; i < x; i++) {
//code...
}
or a while loop
while (condition is true) {
//code...
}
Just switch out the variables as needed to adjust how long the process runs. Or really anything else you need to adjust.
I am using a service to replace the words of an article with synonyms, the API of the service has a limit of 60 requests per minute. I have two functions, the first one get the article and split it into an Array, then calls the other to replace the words, I tried to do that by setting timeout to the second so it will be called first and then after 60 seconds, and then after 120 secs... so every minute I will call the service at most 60 times.
generateArticle : function(data){
Art.words = data.split(" ");
for(var j=0; j<Art.words.length/60; j+=1){
setTimeout(Art.generateSector(j*60),j*60000);
}
},
generateSector : function(position){
var count = 0;
for(var i=position; i<Art.words.length; i+=1){
if(Art.words[i].length > 3 && isNaN(Art.words[i]) && count < 60){
Art.findsimilarword(Art.words[i],i);
count++;
}
}
},
but what is happening is that the second function is called immediately, so in an article with 400 words the first 60 words will be replaced correctly but for the rest 340 words I am getting an error 429 (Too Many Requests) . Am I using the setTimeout with a wrong way? Can someone explain to me why this is happening?
This code:
setTimeout(Art.generateSector(j*60),j*60000);
calls Art.generateSector immediately, passing in j*60, and then takes its return value and passes it to setTimeout, exactly the way foo(bar()) calls bar and passes its return value into foo.
To schedule a call to the function, you pass in a function reference. In your case, you can probably use Function#bind:
setTimeout(Art.generateSector.bind(Art, j*60),j*60000);
Function#bind returns a new function that, when called, will call the original with the given value as this (in our case, Art) and any additional arguments you provide.
Function#bind is an ES5 feature. If you have to support really old JavaScript engines like the one in IE8, this feature can be "shimmed" ("polyfilled"). Search for "function bind shim" or "function bind polyfill" to find multiple options.
I Have learnt a new thing/concept in javascript. calling function using another function as parameter, please have a look at this fiddle examples
Passing function as parameter
ProgressBar(1, 2, function() { flag=true; console.log(' After flag : '+flag);}, flag);
Normal Function.
ProgressBar(1, 2, flag);
Looking at the console statements i have understood what is the effect, but little confused where will this concept prove much important/useful.
JavaScript is async language and compiler continuously read the next line and do not wait for returning value of the function. So in that case, if our operation depends in some other operation then we cannot achieve this by using simple function in "JavaScript".
Like I say, in creating examination mark-sheet. I need to have total or sum value of all subject's obtained marks. After calculating the total I will be able to calculate percentage and if I don't have total marks then I cannot calc percentage.
Example :
function getObtainedMarks(student_id){
//get the total marks from server and it takes little more time
return obtained_marks;
}
function calcPercentage(obtained_marks,total_marks){
return ((obtained_marks/total_marks)*100);
}
var total_marks = 500; var obtained_marks = getTotalMarks(101);
var percentage = calcPercentage(obtained_marks,total_marks);
in the above example, the final value of percentage would be undefined because when we called getObtainedMarks, it was calculating the total by sending request to server but in the mean time compiler moved to next statement i.e var percentage = calcPercentage(obtained_marks,total_marks);
So, here JavaScript introduces callback functions, we actually bind our operation on some dependent operations.
For Example:
function getObtainedMarks(student_id,callback){
//get the total marks from server and it takes little more time
callback(obtained_marks);
}
function calcPercentage(obtained_marks,total_marks){
return ((obtained_marks/total_marks)*100);
}
var total_marks = 500;
getTotalMarks(101,function(obtained_marks){
var percentage = calcPercentage(obtained_marks,total_marks);
});
In the above example, calcPercentage(obtained_marks,total_marks) will not call until getObtainedMarks callback the value of of obtained_marks. So, this is the difference between these 2 kind of functions in JavaScript and I also posted the example for your guidance.
The most common usecase is where you want a function to be called only after something else has happened.
function andAlertTheUser() { ... }
setTimeout(andAlertTheUser, 5000);
document.addEventListener('click', andAlerttheUser);
xhr.addEventListener('load', andAlertTheUser); xhr.send();
The other is where you have an API that performs an operation on multiple things, and you want that operation to be customisable from any code that calls that API.
function doSomethingToEachItemInTheArray() { ... }
var arr = [1,2,3,4]
arr.forEach(doSomethingToEachItemInTheArray);
Sorting is a good example. For example you may want to have your own sorting logic to sort the Array.
var arr = [20,4, 51, 22, 44];
function sortAsc(a, b){
return a>b ? 1 : -1;
}
arr.sort(sortAsc); // passing your sorting logic as a function to sort method.
console.log(arr); // prints [4,20,22,44,51]
Someone know if after I displays an HTML page I can access a specific ID (getElementById), and change it a value several times?
I want to present a client-side some string and change it several times according the progress of the program, but I can not, it writes to me only recently.
For example:
<script type="text/javascript">
function foo(){
for(var i = 0; i<10000; i++){
document.getElementById('myTag').innerHTML = i;
}
}
</script>
In this case, I do not see the numbers run. I see only the last one.
If I put alert inside the loop - the value is changed.
As i understand your question you want a countup from 0 to 10000 ?
and you want to see the progression on screen ? you could do something like that :
http://jsfiddle.net/camus/ayJFM/
var interval = 500;//milliseconds
var foo = (function () {
var i = 0;
var func = function () {
if (i < 10000) {
document.getElementById("myTag").innerHTML = i;
i += 1;
setTimeout(func, interval);
}
};
return func;
})();
setTimeout(foo, interval);
You're almost there. The only thing you're doing wrong is replacing the innerHTML content instead of adding to it. Change this:
document.getElementById('myTag').innerHTML = i;
to this:
document.getElementById('myTag').innerHTML += i;
Additional/alternative answer:
Wait. I've just reread your question and realized that there is another way of interpreting it. The way you ask it is quite vague so I'm leaving the above answer as is.
The reason you don't see "running numbers" as you process the for loop is because you misunderstand how javascript works in the browser.
The browser's event loop runs something like this:
1. Fetch content
2. Run javscript
3. Render content
then repeat forever
This is how javascript works. So running a simple for loop like you're doing. The browser executes the script until there is nothing else to execute (step 2). Once javascript have finished executing then it will start the render process (step 3). Obviously, by this time the value of i is the final value and therefore you only see the final value.
The browser never interrupts running javascript to render/update the page. So, how do people implement countdown timers etc? They do it by scheduling a piece of javascript to execute in the next iteration of the event loop. That is to say, the let the browser enter step 3 and at the appropriate moment as the browser enters step 2 again they run the script they want.
Javascript basically provides two ways to do this: setTimeout and setInterval.
How setTimeout works is this:
step 1. nothing to do
step 2. setTimeout schedules a piece of javascript to run at a later time
Note that the javascript does not execute yet until setTimeout
expires.
step 3. let the browser update the page
many, many loops of steps 1-3
step 2 (some time later).
setTimeout expires and the piece of javascript executes
step 3. let the browser update the page
So, the get the effect you want, you need to do it like this:
function foo(){
var i = 0;
var update = function(){
document.getElementById('myTag').innerHTML = i;
i++;
if (i<10000) {
setTimeout(update,100);
}
};
update();
}
I am using Selenium to test a web app that uses Dojo, and it uses java script to display certain elements. I want to wait until all of the elements are desplayed before I try to manipulate the page, however I am having trouble.
I have started by waiting for the dojo inFlight variable to be 0, this says that all ajax has finished. This doesn't always work because it seems to do some things on a timeout afterwards.
I have also tried repeatedly looking for the element, but this isn't too nice, as perhaps there is some javascript later which will use this field in some way.
So basically I want a method (in firefox at least) to query the javascript waiting to run on a setTimeout (or setInterval) I could even cope with a way of wrapping the built in call through a function of my own just to keep track of this.
Any thoughts or suggestions appreciated!
Every function in JavaScript can be replaced. Consider something like this:
window.originalSetTimeout = window.setTimeout;
window.setTimeout = function(func, delay, params) {
window.timeoutCounter++;
window.originalSetTimeout(window.timeoutCallback, delay, [func, params]);
}
window.timeoutCallback = function(funcAndParams) {
window.timeoutCounter--;
func = funcAndParams[0];
params = funcAndParams[1];
func(params);
}
Then:
selenium.waitForCondition("window.timeoutCounter == 0");
Whenever you call setTimeout of setInterval -- a timer id is returned.
Save that timer id in an array
Inside the function that you're calling on the timeout, pop that timer id off the array. Because we have to remove that id from the array as soon as the timer ends.
Any time you want to check the no. of active timers, just query the length of that array.
Another approach could be like this
const timeoutIndexThen = setTimeout(() => {});
// Some code that might call timeouts...
const timeoutIndexNow = setTimeout(() => {});
const countOfTimeoutsFiredSinceThen = timeoutIndexNow - timeoutIndexThen - 1;
It is based on the fact that each timeout will return a number that is greater by 1 on each call.
So we create some dummy timeout just to get this number at some point.
Then, after a while we call it again and we get a new number. Difference between those numbers is how many times interval was called in between.
Downside of this is that you have to actually create the timeout. Upside is that you don't have to modify original function.