Is there a way to block javascript until requirejs has loaded the files?
I thought doing the following would work because I don't have a callback.
var requireFile = require(['example']);
but it is still asynchronous.
If I do have a callback specified is there a way to block until example is loaded, then execute the callback.
For example.
require(['example'], function(){
console.log('hello');
});
console.log('world');
Console should therefore be:
-hello
-world
I am seeing
-world
-hello
You can wrap the code you want to delay in a function, then call that function from the require callback.
require(['example'], function(){
console.log('hello');
world();
});
function world() {
console.log('world');
}
You can't block until it returns. But you usually don't have to.
You probably have some code that depends on the return from 'require', that code needs to go in the callback (or get called from inside the callback)
It can be a problem when you already have a bunch of code but its the only way to do it.
Sometimes you can have the other code not run until it sees that something it needs has loaded.
Sometimes you can just skip it running and it will get invoked later. Sometimes you have to set up a timer that keeps looking for that 'something' and then pausing a bit if not.
Related
I want to preface by saying I've viewed a lot of stackoverflow questions regarding this topic, but I haven't found any 'duplicates' per se since none of them contain solutions that would solve this specific case.
I've mainly looked at How do I return the response from an asynchronous call?, and the section on 'Promises with async/await' would work inside an asynchronous function, but the function I'm working on is not async and is part of an existing codebase that I can't change easily. I wouldn't be able to change the function to async.
The section on callbacks wouldn't work either, which is explained further below. Anyway, I'll jump into my question:
I'm editing a function (standard function, not async) in JavaScript by adding an asynchronous function call. I want to wait until the async call finishes before I return from the function (since the result of the async call needs to be included in the return value). How would I do so?
I looked into using callbacks, which would allow me to write code which is guaranteed to run only after the async call completes. However, this wouldn't interrupt the flow of the program in the original function, and the original function could still return before the callback is run. A callback would allow me to execute something sequentially after the async function, but it wouldn't allow me to wait for asynchronous call to complete at the highest level.
Example code, which wouldn't return the desired result:
function getPlayers() {
... other code ...
let outfieldPlayers = asyncGetOutfieldPlayersCall()
... other code ...
allPlayers.add(outfieldPlayers)
return allPlayers // the returned value may or may not include outfield players
}
The actual problem I'm facing is a little more complicated - I'm calling the async function in each iteration of a for loop, and need to wait until all calls have completed before returning. But, I think if I can solve this simpler problem, I can solve the problem with a for loop.
Sadly, it is pretty much impossible to wait for async code in a synchronous way. This is because there is no threading in JS (most JS runtimes, but some are). So code is either synchronous or asynchronous.
Asynchronous code is possible because of the event loop. The event loop is part of the javascript runtime. It works by keeping a stack of callback functions that run when events trigger them - usually either timeout events (which you can set with setTimeout()) or IO events (which happen when you make disk or HTTP requests, or on user interaction). However, these callbacks only run when no other code is running, so only when the program is idle and all functions have returned.
This means that techniques like "spin loops" (where you just run a loop until a condition is changed by another thread) that work in threaded environments don't work because the async code won't run until the spin loop finishes.
More Info: https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
If you are using NodeJS, this is possible through execSync.
This requires you to place your asynchronous code in a separate file, spawn a separate process using execSync, which will wait until it exits.
For example, consider the following async function which prints an array.
// task.js
(async function() {
await new Promise((resolve) => setTimeout(() => {
console.log(JSON.stringify([3,4,5]));
resolve();
}, 1000));
})();
Now, you can invoke this from your main process:
function asyncGetOutfieldPlayersCall() {
const execSync = require('child_process').execSync;
return JSON.parse(execSync("node task.js"));
}
function getPlayers() {
let allPlayers = [1,2];
// ... other code ...
let outfieldPlayers = asyncGetOutfieldPlayersCall();
// ... other code ...
allPlayers = allPlayers.concat(outfieldPlayers)
return allPlayers;
}
I have a function that looks like this:
main.add = function(){
var newTabId;
chrome.tabs.create({"url":"enter.html","active":true},
function(tab) {
newTabId = tab.id;
}
);
console.log(newTabId);
}
But when newTabId is printed to console the chrome.tabs.create function hasn't run so the var is undefined.
Is there any way to ensure the code from the chrome namespace finishes before running anything below it?
First, do newTabId global, defining it outside the function. Your two "newTabId" belong to different namespaces.
Secondo, the function inside chrome.tabs.create will start after your main code finish. It's asynchronous programming. chrome API is all asynchronous, so, get used to it, there's no workaround, sadly.
If you want to start thinking asynchronous, I recommend using promise with jQuery's deferred.
I am quiet new to javascript, can not understand that why all javascript calls are asynchronous,
for example, we have calling with order like
call_function1;
call_function2:
if function2 is depend on the results of function1, that can not be ensured, because the execution is asynchronous. Is that true ? And why ?
If true, how to ensure they are synchronous.
If this is duplicated question, I am sorry, because it is quiet new for me.
Thanks fo your answer first.
JavaScript calls are synchonous. If second function depends on results of first function, you might use callbacks model.
function foo(callback) {
var results = // get some results;
callback(results);
}
function boo(results) {
// do something with results here..
}
foo(boo);
No Javascript has functions that guarantee order and behave much like other languages. For example:
function f1() {
alert(1);
}
function f2() {
alert(2);
}
f1();
f2();
You will always get 1 and then 2. What's more is AFAIK javascript runs on one thread so you don't have to worry about race conditions either.
The asynchronous part of javascript comes from waiting on events. For example if you make 2 ajax requests (the a in ajax standing for asynchronous is a hint), you cannot guarantee which will come back first and thus if you have different callbacks for the two requests, you can't guarantee which will be called first.
Calling two functions in a row is definitely not asynchronous.
In fact.. javascript is 100% synchronous. Unless you use 'web workers' all javascript will always run in a single thread, in a single process. There is never, ever a situation where 2 scripts are running at the same time.
Even if you handle an event, coming from an XMLHTTPRequest for instance, the event will only be triggered after all other javascript code has stopped executing.
As mentioned in the comments to your question, JavaScript function calls are usually not asynchronous. The following will be executed in order:
function sayHello() {
console.log("Hi");
}
function sayBye() {
console.log("Bye");
}
sayHello();
sayBye();
The above code will first print "Hi", then "Bye", as the calls to sayHello and sayBye are in that order.
However, if a function does perform some action asynchronously, and you have another function that relies on the result of that, you can supply the second function as a callback to the asynchronous request. For example:
xmlHttpRequestObj.onreadystatechange = function() {
if(xmlHttpRequestObj.readyState == 4 && xmlHttpRequestObj.status == 200) {
//Asynchronous call returned successfully. Do something that relies on that here.
}
}
I don't know how you say that "Javascript is generally said to be asynchronous". It is generally the opposite: Javascript is almost always not asynchronous.
So generally (no ajax, no callback, no event handling), the following functions calls will execute sequentially.
function1();
function2();
If you are assigning both these functions to a single event, both will be called concurrently, but will not be executed in parallel. Same if both are called at the same time (using setTimeout), or as an Ajax callback. See Is JavaScript guaranteed to be single-threaded? for a very good explanation.
You could have heard that Ajax is asynchronous. That is true when you consider the request to servers without interfering with the user, "in the background". But this does not mean that Javascript is asynch. In fact even with Ajax calls, the javascript part is single threaded.
I'm trying to figure the best way to get my functions executing in the correct order.
I have 3 functions
function 1 - squirts OPTIONs into a SELECT via JSON and marks them as selected
function 2 - squirts OPTIONS into a 2nd SELECT and marks them as selected
function 3 - gets the values from the above SELECTs along with some additional INPUT values, does an AJAX GET resulting in JSON data, which is read and populates a table.
With JQuery Onload, I execute:
function1();
function2();
function3();
I'm finding function3 is executing before the SELECTs have been populated with OPTIONS and hence the table has no results, because the values sent in the GET were blank.
I know this is probably a very simple problem and that there are probably a dozen ways to accomplish this, but basically I need the best way to code this so that function3 only runs if function1 and 2 are complete.
I've come into Javascript via the back door having learnt the basics of JQuery first!
Thanks for your assistance.
Javascript executes synchronously, which means that function3 must wait for function2 to complete, which must wait for function1 to complete before executing.
The exception is when you run code that is asynchronous, like a setTimeout, setInterval or an asynchronous AJAX request.
Any subsequent code that relies on the completion of such asynchronous code needs to be called in such a manner that it doesn't execute until the asynchronous code has completed.
In the case of the setTimeout, you could just place the next function call at the end of the function you're passing to the setTimeout.
In the case of an AJAX call, you can place the next function call in a callback that fires upon a completed request.
If you don't want the execution of the subsequent function to occur every time, you can modify your functions to accept a function argument that gets called at the end of the asynchronous code.
Something like:
function function1( fn ) {
setTimeout(function() {
// your code
// Call the function parameter if it exists
if( fn ) {
fn();
}
}, 200);
}
function function2() {
// some code that must wait for function1
}
onload:
// Call function1 and pass function2 as an argument
function1( function2 );
// ...or call function1 without the argument
function1();
// ...or call function2 independently of function1
function2();
I recommend you use a Promises library. You can hack simple solutions like other answers suggest, but as your application grows, you'll find you are doing more and more of these hacks. Promises are intended to solve these kinds of problems when dealing with asynchronous calls.
The CommonJS project has several Promises proposals which you should check out. Here is a question I asked on SO about Promises a while back with links to other solutions. Learn more about Promises in this Douglas Crockford video. The whole video is good, but skip to just past half way for promises.
I'm using the FuturesJS library currently as it suits my needs. But there are advantages to other implementations as well. It allows you to do sequences very easily:
// Initialize Application
Futures.sequence(function (next) {
// First load the UI description document
loadUI(next); // next() is called inside loadUI
})
.then(function(next) {
// Then load all templates specified in the description
loadTemplates(next); // next() is called inside loadTemplates
})
.then(function(next) {
// Then initialize all templates specified in the description
initTemplates();
});
Even more powerful is when you need to join async events together and do another action when all of the other async events have completed. Here's an example (untested) that will load a bunch of HTML files and then perform an action only once ALL of them have completed loading:
var path = "/templates/",
templates = ["one.html","two.html","three.html"],
promises = [];
$.each(templates, function(i,name) {
promises[i] = Futures.promise();
var $container = $("<div>");
$container.load(path+name, function(response,status,xhr) {
promises[i].fullfill();
}
});
Futures.join(promises, {timeout: 10000}) // Fail if promises not completed in 10 seconds
.when(function(p_arr) {
console.log("All templates loaded");
})
.fail(function(p_arr) {
console.log("Error loading templates");
});
This might be overkill for your application. But if the application is growing in complexity, using promises will help you in the long run.
I hope this helps!
invoke function2 inside of function1 and function3 inside of function2.
It's not clear why f1 and f2 are executing before f3.
Also, are you using the preferred $(document).ready() or some variation of onload?
It might be helpful if you provide a reproducible test case.
fun3() will only run after both are ready. It might run twice. You can fix this with a lock inside fun3() you would need a Singleton to guarantee it works correctly.
var select1ready = false, select2ready = false;
fun1()
{
// do stuff
select1ready = true;
fun3();
}
fun2()
{
// do stuff
select2ready = true;
fun3();
}
fun3()
{
if (select1ready && select2ready)
{
}
}
fun1();
fun2();
I know there is a method like this :
setTimeout("functionA();",1250);
That can delay my process, but the problem is , the functionA have some value to return. When I use this way, it is not get me back the functionA return value:
this.sth = setTimeout("functionA();",1250);
I means, this.sth is not the result I want.
You should make a functionB() that does this:
function functionB() {
this.sth = functionA();
// do things with the returned value
}
You could do:
setTimeout(functionA(functionB()), 1250);
and define functionB as:
function functionB(resultFromA) {
}
and functionA would look like:
functionA(callback) {
// do something useful
callback(result);
}
setTimeout is an asynchronous operation. This means that functionA gets run after the timeout but the rest of the script keeps running. It's a common mistake new javascript programmers make to think the script will be pausing when causing this.
If you goal is to make the script pause your better off using a while loop or for loop with dates. This is probably a bad idea though. A scrip that pauses can do weird things to browsers including making the whole browser pause while it runs. That includes all the tabs. This is probably not what you want. The better bet is to do like Garret mentioned and make it so that the operation works asynchronously but still accomplishes what you wanted.
i've seen solutions to this using for loops with thousands/millions of iterations. However be warned this can make the browser unresponsive if used incorrectly.