I am working on a library that will expose 3 methods. All three of these methods depend on another library (lets call it libA) having been loaded and that library loads asynchronously.
I could write the code to expose the methods as soon as the JS file has finished loading but then the user would have to defer execution until libA has finished.
I was hoping to, rather, expose "a version" of those 3 methods immediately while libA continues to load asynchronously in the background. Any calls to those 3 methods would get queued up until libA is done loading. And after libA is done loading those 3 methods would get replaced with the real one and the queue would be processed.
Let's say I have this:
var myLib = (function(){
// expose 3 functions for the user to use
return {
"func1" : function(opts){},
"func2" : function(opts){},
"func3" : function(opts){}
}
})();
This library will be loaded by the user. At the same time libA will also be loaded. It may take longer to load then mine or it may finish before mine starts.
So if the user runs myLib.func1({}) and libA has not finished loading then it should get queued up and then when libA is done it should execute. If, on the other hand, libA has finished loading then it would execute immediately.
My initial thought is to do something like this:
var myLib = (function(){
// queue the calls
var queue {
"func1" : [],
"func2" : [],
"func3" : []
};
// the "temp" functions that just add them to the queue
var ret = {
"func1" : function(opts){ queue.func1.push(opts); },
"func2" : function(opts){ queue.func2.push(opts); },
"func3" : function(opts){ queue.func3.push(opts); }
}
// this may happen before the user users my library or after
// if it happens before then the functions will be replaced before the user calls them and they won't need to be queued
// if it happens after then the functions will get replaced and the queued up ones will be executed
waitForLibAToFinish(function(){
ret.funct1 = function(opts){alert("this is the real func1");},
ret.funct2 = function(opts){alert("this is the real func2");},
ret.funct3 = function(opts){alert("this is the real func3");},
// process the queue
for(var i = 0; i < queue.func1.length; ++i)
{
ret.func1(queue.func1[i]);
}
// repeat for func2 and func3 queue
});
return ret;
})();
But this just seems like a bad way to do it. Plus I'll have to have a queue for each function and call each one. There must be a way to abstract that part out so its more generic for all the methods my library exposes.
I'm open to any ideas/suggestions. I just cannot (for numerous reasons out of my control) use any 3rd party libraries like Promise or JavaScript. And, my code has to work on IE8. Trust me, I hate it more than you do.
===
I'm adding some more context/details.
I know I mention SharePoint but this is not an SP specific question.
I am building a library that offers convenience methods to simplify otherwise complicated tasks in SharePoint. All my library does is call SP libraries. The relevant SP libraries are loaded asynchronously. So one of two things needs to happen:
Either the user needs to wait for the relevant SP libraries to finish loading before calling any of the methods in my library
Or my library needs to wait for the relevant SP libraries to finish
The function SP offers to let you "queue" up your function until a relevant SP library is loaded is ExecuteOrDelayUntillScriptLoaded.
My library is currently built on the first option. I wanted to simplify the experience for the user so they don't have to check (by way of ExecuteOrDelayUntillScriptLoaded). I could change it to the 2nd way but there are reasons I don't want to.
Instead, what I was hoping to do is include 1 check in my library with ExecuteOrDelayUntillScriptLoaded that would "modify" what my library does. Before the relevant libraries are done loading my library would just queue up the calls. And after it is done loading and ExecuteOrDelayUntillScriptLoaded fires, my code would:
Execute everything in the queue
Modify each function my library exposes to directly execute and not queue
Don't do the queuing yourself. Leave the library loading and dependency resolution to the user. Just expose a function that instantiates your library, the user may call it when library A is ready and get the module with usable methods back.
There even already is a standard on how to do that: Asynchronous Module Definition. (You don't need require.js as a third-party library, you can implement the bare essentials yourself)
If the user wants (needs) to call your library methods before everything is loaded, they can always queue the premature invocations themselves in any manner they want. But usually this should not be necessary.
Related
I'm wondering if there's a way to cause JavaScript to wait for some variable-length code execution to finish before continuing using events and loops. Before answering with using timeouts, callbacks or referencing this as a duplicate, hear me out.
I want to expose a large API to a web worker. I want this API to feel 'native' in the sense that you can access each member using a getter which gets the information from the other thread. My initial idea was to compile the API and rebuild the entire object on the worker. While this works (and was a really fun project), it's slow at startup and cannot show changes made to the API without it being sent to the worker again after modification. Observers would solve part of this, and web workers transferrable objects would solve all, but they aren't adopted widely yet.
Since worker round-trip calls happen in a matter of milliseconds, I think stalling the thread for a few milliseconds may be an alright solution. Of course I would think about terminating in cases where calls take too long, but I'm trying to create a proof of concept first.
Let's say I want to expose the api object to the worker. I would define a getter for self.api which would fetch the first layer of properties. Each property would then be another getter and the process would continue until the final object is found.
worker.js
self.addEventListener('message', function(event) {
self.dataRecieved = true;
self.data = event.data; // would actually build new getters here
});
Object.defineProperty(self, 'api', {
get: function() {
self.dataRecieved = false;
self.postMessage('request api first-layer properties');
while(!self.dataRecieved);
return self.data; // whatever properties were received from host
}
});
For experimentation, we'll do a simple round-trip with no data processing:
index.html (only JS part)
var worker = new Worker("worker.js");
worker.onmessage = function() {
worker.postMessage();
};
If onmessage would interrupt the loop, the script should theoretically work. Then the worker could access objects like window.document.body.style on the fly.
My question really boils down to: is there a way to guarantee that an event will interrupt an executing code block?
From my understanding of events in JavaScript, I thought they did interrupt the current thread. Does it not because it's executing a blank statement over and over? What if I generated code to be executed and kept doing that until the data returned?
is there a way to guarantee that an event will interrupt an executing code block
As #slebetman suggests in comments, no, not in Javascript running in a browser's web-worker (with one possible exception that I can think of, see suggestion 3. below).
My suggestions, in decreasing order of preference:
Give up the desire to feel "native" (or maybe "local" might be a better term). Something like the infinite while loop that you suggest also seems to be very much fighting agains the cooperative multitasking environment offered by Javascript, including when thinking about a single web worker.
Communication between workers in Javascript is asynchronous. Perhaps it can fail, take longer than just a few milliseconds. I'm not sure what your use case is, but my feeling is that when the project grows, you might want to use those milliseconds for something else.
You could change your defined property to return a promise, and then the caller would do a .then on the response to retrieve the value, just like any other asynchronous API.
Angular Protractor/Webdriver has an API that uses a control flow to simulate a synchronous environment using promises, by always passing promises about. Taking the code from https://stackoverflow.com/a/22697369/1319998
browser.get(url);
var title = browser.getTitle();
expect(title).toEqual('My Title');
By my understanding, each line above adds a promise to the control flow to execute asynchronously. title isn't actually the title, but a promise that resolves to the title for example. While it looks like synchronous code, the getting and testing all happens asynchronously later.
You could implement something similar in the web worker. However, I do wonder whether it will be worth the effort. There would be a lot of code to do this, and I can't help feeling that the main consequence would be that it would end up harder to write code using this, and not easier, as there would be a lot of hidden behaviour.
The only thing that I know of that can be made synchronous in Javascript, is XMLHttpRequest when setting the async parameter to false https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Parameters. I wonder if you could come up with some sort of way to request to the server that maintains a connection with the main thread and pass data along that way. I have to say, my instinct is that this is quite an awful idea, and would be much slower than just requesting data from the main thread.
For what I know, there is not something native in JS to do this but it is relatively easy to do something similar. I made one some time ago for myself: https://github.com/xpy/whener/blob/master/whener.js .
You use it like when( condition, callback ) where condition is a function that should return true when your condition is met, and callback is the function that you want to execute at that time.
Is it possible to execute setTimeout() or setInterval() synchronously so that further execution that depends on its callback will not cause a not defined error?
intv = window.setInterval(function() {
// do some stuff
doSomeStuff();
// kill interval when stuff is done
if (stuffIsDone)
window.clearInterval(intv);
}, 10);
// dependent on "stuff" being done
// I want this to execute only after intv is cleared
doMoreStuff();
I don't want to put every consecutive call inside of a timeout to check if (typeof someStuff != 'undefined')
Yes, I do understand that this will cause a delay in loading and possible the UI. The intervals will be extremely small and inconsequential.
EDIT... Alright, what I'm ultimately trying to do is dynamically add a number of javascript files dynamically, by only including a single javascript file.
ie.:
// auto include all javascript files
<script language="javascript" type="text/javascript" src="include.js"></script>
This works by requesting the JSON list of javascript files from the server via AJAX. It loops through the list and adds the scripts dynamically to the DOM.
The catch:
If I add the scripts using setInterval, they are sometimes added after the onLoad event fires, depending on the current computational load of the machine executing the code. So, when I call functions from one of the files onLoad, it causes an error (because at the time of execution, the function didn't exist)
If I add the scripts inside of a while loop, the dynamically added scripts to do not execute and the internal references between the scripts are invalid and error out.
So, the question really is: without using setInterval and typeof on every call, how do I dynamically add scripts reliably so that dependent code doesn't attempt to execute before the depended-upon scripts are loaded?
Take a look at Refactoring setInterval-based Polling and consider converting your setInterval to a setTimeout and use a Promise to execute doMoreStuff() after stuffIsDone is true.
That article is from 2013, so consider Promises/A+ (using a polyfill for ES6-style Promises for older browsers) instead of jQuery's or Underscore's implementation.
You can run a while loop and keep track of the system time if you want to block the JavaScript thread for a fixed period of time.
For example:
var startMillis = Date.now();
while (Date.now() - startMillis < 10);
Note that no other code will run during this period. JavaScript is single threaded.
Don't know exactly what you're trying to do, but this seems a little strange :)
Is 'require' synchronous in AMD (asynchronous module definition)? If so, what makes this specification asynchronous? What if I have require() (and it hasn't been loaded yet) in the middle of my code, will it stall execution? Talking browser-side.
There are two different synchronous concepts here.
The first is "Will it stop my entire webpage, and sit and wait for the file.".
The answer is no. RequireJS doesn't do that if you've got a script with dependencies.
If you use it appropriately, it uses a promise-system.
What that means is that if you send in your callback and define your requirements for that file, the callback won't be run until all of the required files are loaded.
If there's a require inside of one of those required files, then THAT callback won't be run until ITS dependencies have loaded.
The outermost callback (the one that would be at the bottom of your script, normally), won't run until everything inside has.
This works on a promise system.
It's worth understanding how promise systems work (similar to an observer-pattern, in a way).
They're meant to be passed around or chained, based on an event, rather than having multiple people listen in any order.
var widget = new Widget(),
widgetLoaded = widget.load(url); // return a promise to let the program use the widget
widgetLoaded.then(function () { widget.move(35); })
.then(function () { widget.setColour("Blue"); })
.then(function () { widget.show(); });
This is like returning this so that you can chain function calls, except that the calls don't actually happen until widget.load() completes.
The widget will actually control when this happens, by keeping its promise if the widget loads and everything is fine, or by breaking its promise if something went wrong.
In most promise systems, .then or whatever they call it, either takes two functions (kept and broken -- in my systems, brokens are always optional), or they take an object with success and failure -- $.ajax does this, and then lets you predetermine what you want to do with the data when it's loaded, or if it fails -- promises.
So your page still work 100% asynchronously (without interrupting the UI), but it's 100% synchronous in that all of the modules will fire in the right order.
One thing you MUST REMEMBER:
If you have these dependencies in your code, you can not have any dependencies lying around at the bottom of your script, waiting to run, inline.
They must all be locked away inside of your callback, or locked inside a function waiting to be called by your callback.
This is simply because it is an asynchronous process, in terms of actual processing, and will not block the browser from running events/JS, rendering the page, et cetera.
For requireJS:
You have to pass a callback method alongside the required modules to .require(), that will get fired when the resources were loaded successfully. So, of course you should/can only access loaded AMD or CommonJS modules just within that callback.
for NodeJS:
Yes, .require() does work synchronously. NodeJS uses the CommonJS module system, not AMD.
I'm currently experimenting with embedding V8 in a project of mine. Since I use libev for listening to sockets and events and want to be able to script events with JS I would want to be able to just run v8 for a short while and then jump back to C++ to check for events and such and then go back to running JS-code. Since I haven't done much script embedding earlier I'm sure there are some clever way that this usually is done in so all ideas are appreciated.
The cleanest way I found of doing this is to create setTimeout and clearTimeout functions within JS. setTimeout creates a ev::Timer which has a callback that gets called after a certain amount of time. This makes it so that when you call a JS function you continue to execute that until it returns, but that function can set a number of timeouts which aren't called until after you exit the current JS and there hasn't happened any other libev events during the execution, in that case those are handled first (in C++). The limitations of this method is that the coder who writes JS has to remember to not write functions that goes into eternal while-loops or similar. A loop is instead done like this:
function repeat() { setTimeout(repeat, 0); }
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.