Disclaimer. A friend of mine looking for a job of senior JS programmer sent the question to me. It's not a real problem then, but since I can imagine where and how it could become real, I've decided to post it here.
The question (a test task). It follows in my words, I can quote it here, if you think I got it wrong. How to write a function which sends asynchronously requests to a given array of URLs, concatenates the result of each request and returns the concatenated string? Oh, and there is another limitation: IE9+, current FF, current Chrome. The friend's answer (as polite as possible): no can do.
My answer was the same. Since there are no threads in browser JS (it's not NodeJS) and there is no sleep function, you cannot wait until all requests are processed. Web workers? They aren't supported in IE9. Also, they wouldn't help anyway. You can send the requests one-by-one, using sync flag of XMLHttpRequest.open but (here is my suggestion) if all requests are being sent to the same server which does some math that can be executed on a single CPU core only, your penalty is x4/x8/x16 times. Anyway, it's prohibited by the test task. Of course, you can concatenate the results in a callback function, but it's prohibited as well, since you must return the result.
But I'm not a JS guru, so I forwarded the question to my another friend who is (I think so). He suggested creating additional browser tabs, one per URL, which would send the request and write the result in its title. The main tab would loop thru the tabs, waiting until all the titles aren't empty. Since the tabs are executed independently, it should work. Then he tried the solution and said it works in IE only (with some side effects). In other words, no solution.
But the employer replied to my first friend with a statement the solution exists, though refused to send JS code of the function.
So, is the question a some kind of trolling? Or there is a solution I will be able to use if I ever face a situation when I really MUST concatenate async requests results (I know it's a bad idea in JS).
Here's a discussion of various options:
Use synchronous Ajax and return the result. Synchronous ajax is a horrible idea and the challenge said to use async requests so presumably this is a no-go, but I include it here because it does let you directly return the result.
If you use async ajax in the same window, then you simply cannot return the result directly. You can call a callback when the result is done or you can return a promise which will then call a .then() handler callback when the result is available. You cannot spin and wait for the async ajax to finish because the Ajax complication can't get back to you until you return and let the event queue get to the next events.
If you put Ajax into a webWorker (either synchronous or asynchronous), you can code the webWorker however you want, but the only way it can communicate back to the main thread is via a message and that message can't be received by the main thread until you return back from your original function to get to the next messages in the event queue. Again, you can't spin and wait for the message from the webWorker because it won't get back to you until AFTER the current thread of execution finishes. So, you have to return from your function BEFORE you can get the result from the webWorker.
You can put the Ajax into an iFrame or another window and then communicate back to the current window from the other window when it is done. This has all the same issues as the previous solutions in that you won't be able to receive communication back from the iFrame or other window until after the current function has finished and returned so that events can get processed off the event queue. So, you have to return from your function BEFORE you can get the result from another window.
You can put the Ajax into an iFrame or another window and then poll some variable in that window from your main window. There is a possibility that this might work in some browsers, but I was unable to build a successful test to prove it could work.
1st thought:
function concatenatesResults(urls, cb) {
var temp = [], i = urls.length
urls.forEach(function (url, key) {
//its async so not block the foreach
$.ajax({
url: url,
success: function (data) {
temp[key] = data //be sure it is in a good order
i--
if (i === 0) cb(temp.join("")) //if this is teh last one return the data
}
})
})
}
concatenatesResults([/* URLS*/], function(data){console.log(data)})
Related
ive found out that its a best practice for nodeJS / ExpressJS as an API-Endpoint for a ReactJS Software to only use asynchornus functions for mysql-querys etc.
But i really dont get how this should work and why it decrease performance if i didnt use it.
Please imagine the following code:
API Endpoint "/user/get/1"
Fetches every datas from user with id one and responds with a json content. If i use async there is no possibility to respond with the information gathered by the query, because its not fulfilled when the function runs to its end.
If i wrap it in a Promise, and wait until its finished its the same like a synchronus function - isnt it?
Please describe for me whats the difference between waiting for a async function or use sync function directly.
Thanks for your help!
If i wrap it in a Promise, and wait until its finished its the same
like a synchronus function - isnt it?
No, it isn't. The difference between synchronous and async functions in JavaScript is precisely that async code is scheduled to run whenever it can instead of immediately, right now. In other words, if you use sync code, your entire Node application will stop everything to grab your data from the database and won't do anything else until it's done. If you use a Promise and async code, instead, while your response won't come until it's done, the rest of the Node app will still continue running while the async code is getting the data, allowing other connections and requests to be made in the meantime.
Using async here isn't about making the one response come faster; it's about allowing other requests to be handled while waiting for that one response.
One could simply encapsulate number of synchronous requests as an asynchronous request.
The "func" parameter within the below code could for example contain multiple synchronous requests in order. This should give you more power over data contrasting the use of the DOM as a medium to act on the data. (Is there another way?, it has been a while since I used javaScript)
function asyncModule(func)
{
"use strict";
var t, args;
t = func.timeout === undefined ? 1 : func.timeout;
args = Array.prototype.slice.call(arguments, 1);
setTimeout(function () {
func.apply(null, args);
}, t);
}
Now something must be wrong with my reasoning because here is what the specs says:
Synchronous XMLHttpRequest outside of workers is in the process of being removed from the web platform as it has detrimental effects to the end user's experience. (This is a long process that takes many years.) Developers must not pass false for the async argument when the JavaScript global environment is a document environment. User agents are strongly encouraged to warn about such usage in developer tools and may experiment with throwing an InvalidAccessError exception when it occurs. # https://xhr.spec.whatwg.org/
I would think you would want to avoid async in requests at all costs and instead wrapp sync requests within async function.
Here is the main question along with the follow up.
Is there something wrong with the example I gave?
If not then:
How is forcing requests to be async the right solution?
It goes without saying that you have freedom to debunk any of my "claims" if they are simply wrong or half truths. I am confused over this, I give you that.
Keep in mind that I am testing javaScript in terminal, not in the browser. I used the webserver within GO programming language and everything seems to be working fine. It is not until I test the code within the browser that I get hint for this spec.
This answer has been edited.
Yes I my reasoning was faulty!
There are two angles to think about.
What does async actually mean in javascript?
Can one async call stall another async call?
Async in javascript doesn't mean script will be running in a interleaved/alternating processes with more then one callstack. It can be more like a global timed defer/postpone command that will fully take over once it get its chance. This means async call can be blocking and the nonblocking "async:true" part is only a "trick" based on how xhttprequest is implemented.
This means encapsulating a synchrounous request within setTimeout could be waiting for a failed request that ends up blocking other unrelated async requests where as "async:true" feature would only execute based on its state value.
This means older browser support requires you to chain requests or to use DOM as a medium when you need to do multiple requests that depend on another..Ugh...
Lucky for us, Javascript has threads now. Now we can simply use threads to get clean encapsulation of multiple correlated requests in sync. (or any other background tasks)
In short:
The browser shouldn't have any problems of running request in sync if it is within a worker. Browsers have yet to become OS, but they are closer.
P.S. This answer is more or less because of trial and error. I made some test cases around firefox and observed async request do halt other async requests. I am simply extrapolating from that observation. I will not accept my own answer in case I am still missing something.
EDIT (Again..)
Actually, it might be possible to use xhttp.timeout along with xhttp.ontimeout. See Timeout XMLHttpRequest
This means you could recover from bad requests if you abstract setTimeout and use it as a schedular.
// Simple example
function runSchedular(s)
{
setTimeout(function() {
if (s.ptr < callQue.length) {
// Handles rescheduling if needed by pushing the que.
s = s.callQue[s.ptr++](s);
} else {
s.ptr = 0;
s.callQue = [];
s.t = 200;
}
runSchedular(s);
}, s.t);
}
Does JSVM run just in one thread?
I am wondering how the JavaScript function executing inside the VM.
The source code below is interesting:
// include jQuery as $
function test() {
$.ajax({url:"xxx.com"})
.success(function() {alert("success 1");})
.fail(function() {alert("fail 1");});
$.ajax({url:"yyy.com"})
.success(function() {alert("success 2");})
.fail(function() {alert("fail 2");});
while(true);
}
It will make die loop at the "while" line and never pop up any alert dialog to show neither "success" nor "fail".
We know inside the $.ajax, the VM creates XMLHttpRequest and sends a HTTP request.
After sending out two requests, it meets the "while" line.
Thus I image that the JSVM:
1) can handle only function call at one time. (function is atomic)
2) follow the rule: first comes, first served.
Does my idea right?
Does anyone can explain the internal implementation of JSVM?
More specific,
If using AngularJS to develop a front end app, we would like to do something and then immediately record a log to remote server in form submit event like ng-submit.
function ngSubmitTest() {
doA();
recordA(ajax, remoteServer); // must after doA()
}
If recordA uses AJAX, we should ensure recordA is complete before ng-submit redirect the page meanwhile kill the old page and also the VM (if the old page is killed, the recordA may not complete). One solution is doing AJAX with async=false. And I wonder if there is any other solutions?
Thanks.
The implementation of JS depends on the context you're runing it.
Each browser has it's own implementantion, and they can do whatever they want as long as they follow the language specification.
It shouldn't bother you if it runs on one or multiple threads, but you can be sure JavaScript is not a "threaded" language, it works with an event loop flow, in which an event is fired, and consecutive functions are fired after that, until there is nothing more to call. This is the reason why it's pretty hard to block the UI in JavaScript if you're writing "good" code.
A good example on how this works, and the diferences betwen event loops and classic threading, is node.js, i'll give you a example:
Supose you're listening for a request on a server, and 2 seconds after the request arrives you'll send a message. Now let's supose you duplicate that listener, and both listeners do the same thing. If you request the server, you'll get the two messages at the same time, 2 seconds after the request is made, instead of one message on 2 seconds, and the other one on 4 seconds. That means both listeners are runing at the same time, instead of following a linear execution as most systems do.
Node runs Chrome's V8 if you're wondering, it's a very professional JS interpreter and it was a breakthorugh when it came out.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
return AJAX callback return
I have made a JQuery code using AJAX, but despite all my efforts (trying $.post, $.get and $.ajax) I am not able to get any response nor using it in my code.
Example code:
var r = $.post("ajaxpage.php", function(data) {return data});
console.log(r); // nothing
One of the most common misconceptions of beginner programmers about Javascript and AJAX is to treat the AJAX request as a "normal" function, doing variable assignments or expecting to use immediately the AJAX response in their code.
That's not how it works though; let's try to understand how a correct implementation works.
AJAX stands for Asynchronous JavaScript and XML.
We will ignore for a while the XML part (which is more about how the request is carried on, via XMLHttpObject), the Javascript bit is quite obvious (it's the scripting language we use, with or without JQuery), let's focus on asynchronous.
Think about AJAX this way: it is roughly like sending a work email to a colleague, while you're at work, and giving some info; and requesting an action to be taken and/or other info in return; no matter if your friend answers immediately or not, you still have to continue your job because the answer could be delayed (your friend may be particularly busy today).
When your friends answers with relevant info, only then you will address the matter and take appropriate actions. If an action is requested, your colleague will carry it on only when he receives your email.
AJAX works in a similar way: from client-side, you make a request to a server-side page, and expect an action (like writing a row in a database) or a response (some data fetched server-side from the page you are calling.
The important bit is that your JavaScript code continues its execution regardless of the completion of the round-trip, as there can be a significant delay when your client (remember that JS runs client-side) makes an AJAX call to the server (slow server, slow connection, and so on).
So you can't expect to do things like:
var r = $.post("ajaxpage.php", function(data) {return data});
because $.post doesn't actually "return" a value like a "regular" function, the variable r cannot be valued by $.post
Instead, you should organize your code based on the done event, which is fired after the AJAX call has completed: it guarantees (if there have been no failures, like server-side errors, not found pages, etc.) that we actually have a response to use in your code on success.
With that event we can call a function that receives the response as a parameter and actually uses it.
$.post("ajaxpage.php").done(useMyResponse);
// rest of the code
function useMyResponse(response)
{
// do fancy things with the response like:
console.log(response); // works!
// or maybe
$("#someElement").html(response);
}
A shorthand for this would be:
$.post("ajaxpage.php",function (response) {
// use response
console.log(response);
});
Edit: i'm not a native English speaker, forgive my mistakes.
Well, first I want to say I'm a bit new in the world of Internet dev.
Anyway, I'm trying to know if its possible to run two pieces of code in parallel using javascript.
What I really need is to call two methods that are in a remote server. I pass, for both, a callback function that will be executed soon the data I want is ready. As the server running these functions take a time to answer, I'm trying to find a way to call both methods at the same time without need to wait till the first finishes to call the second.
Does methods like setTimeout run concurrently, for example
setTimeout(func1, 0);
setTimeout(func2, 0);
...
function func1()
{
webMethod1(function() {alert("function 1 returned"); } );
}
function func1()
{
webMethod2(function() {alert("function 2 returned"); } );
}
Edited
I've just found this article that may be very cool for the realease of next browsers: Javascript web workers
There is one single thread of execution in Javascript in normal WebBrowsers: your timer handlers will be called serially. Your approach using timers will work in the case you present.
There is a nice piece of documentation on timers by John Resig (author of the very popular jQuery javascript framework - if you are new to Web development, I would suggest you look it up).
Now, if you are referring to HTML5 based browsers, at some point, they should have threading support.
Yes, that's exactly how web requests through AJAX work. No need to setTimeout to 0, you can just call them one by one, and make an AJAX request, and it'll be executed asynchronously, allowing you to pass a callback function to be invoked when the request completes.
The means of creating an AJAX request differs some depending on what browser you're running. If you're going to build something that depends considerably upon AJAX, and you want it to work across multiple browsers, you're best off with a library. Here's how it's done in jQuery, for instance:
$.ajax({ url: '/webrequesturl', success: function(result) {
// this will be called upon a successful request
} });
$.ajax({ url: '/webrequest2url', success: function(result) {
// this will be called upon a successful request
// this may or may not be called before the above one, depending on how long it takes for the requests to finish.
} });
Well, JavaScript is single-threaded, the two timers will run sequentially one after the other, even if you don't notice it.
I would recommend you to give a look to the following article, it really explains how timers and asynchronous events work, it will also help you to understand the single-threaded nature of JavaScript:
How JavaScript Timers Work
And as an alternative you could give a look to WebWorkers, is a way to run scripts in separate background threads, but they are only supported by modern browsers.
What you are looking for is asynchronous client-server communication (keyword: async). Asynchronous functions return straight away, but the provided callback will be executed after the specified condition is satisfied.
So, if the function that sends a request to the server is asynchronous, this would let you send both requests to the server without waiting for one to respond.
Using setTimeout may work, as this will schedule both request-sending functions to be called. However, some browsers only run one thread of Javascript at a time, so the result would be that one of the scheduled functions would run and block (waiting for a reply) and the other scheduled function would wait until the first was done to start running.
It is advisable to use async support from your server communication library. For instance jQuery uses async by default.
It depends on the JavaScript engine.