Foreword
This is the third and final part of the article, and for better understanding of this part, I recommend reading the first and second parts first.
Part III
From Previous Parts
The challenge - To create an engine that will implement the JavaScript’s missing functionality of including in js files other js files.
The solutions - A solution that works only if the external files contain functions, or declarations that don't depend on other files and another solution that works in every situation but has one small disadvantage: having to create header files for the source files.
The second isn’t far from meeting the challenge, but not there yet. Can we push further?
Solution 3
The Logic
One of the problems identified back then was that when the execution of a script starts, it goes all the way and from that we have the restriction: all files should contain only function declarations and object declarations (but only if they're not related to objects from other files).
Ideally, only the part with the $include function of the file should be executed – and will name this part header, and then, when the time is right, the rest – body, but as I stated above, it cannot be done.
Let’s think again; how do we stop the execution of a script? For a function you use return, but for the entire script?
Error is the answer!!! When an error occurs the script’s execution is halted! So we throw an error on purpose! The next question will be: But the browser won’t display the error? It will, unless we override window.onerror so that nothing will be shown to the user.
Our code should look like this
$include = function ()
{
//code …
throw new Error(“Special Error”);
}
Window.onerror = function ()
{
//we can check here to see if the message of the error is not “Special Error” //and then show it to the user
}
But 2 problems arise:
1. The execution of the script can be resumed when needed? NO! (But we can execute it all again)
2. Also, what happens when a legitimate error occurs? Can it be shown? (Yes, because we can differentiate through an error from the parser and a personalized error thrown by us).
However there is a more elegant approach: using an iframe.
But how? A solution would be as text file. Next we read the header (that now does not necessarily have to be a function) and then use eval to execute the body. As stated in the first part eval handles badly resources and this makes it totally inappropriate for executing large portion of code as in our case.
The other problem is that IE doesn't load the js file like text, but asks you to download it.
So we will have a html file that will load the script normally and will execute only the $include function that will pass to the parent document the filenames that are dependencies for the file currently loaded in the iframe, and after that we will throw the error.
Also when a file is loaded is cached so, when needed for the main document, isn’t loaded from the server again.
But what happens if the script has no dependencies, therefore no $include function?
Can we force the user to use $include() with no parameters? Yes we can, but also we can wait till the script.onload event is fired and then tell the parent document that this file has no dependencies.
Of course another problem: the script will be executed twice: first in the iframe and second in the main document; and that’s the least of our problems; the code can contain alert, confirm, open etc. that will screw up our work badly by executing in the iframe.
And yet another artifice: overriding window.alert, window.open, window.confirm etc. and not just setting them to do nothing but to stop the execution of the script also.
And that seems to be it!
Let’s recap a bit:
The main page will contain a tree of files that will be created by recursively passing a filename (filepath) to the iframe’s document that will return the dependencies for that file. Here we’ll need an algorithm to check for circular dependencies. And of course the $include function will do nothing in the main page.
After that all files can be added to the main document’s head in the correct order.
Of course we will keep from the first solution we’ll keep the code that lets us specify path relative to the IncludingEngine.js file and not to the current html document, and from the second solution the way the application starts with the Main function.
The Implementation
Unlike the implementations from
the previous 2 parts, this one is much larger, therefore not suited for pasting
it here.
But the most important thing was already presented above: general idea together with the little ideas on how to overcome different barriers.
However you can download this implementation and then examine it. (Don’t
forget: there are 2 files: IncludingEngine.js and LoadFile.htm that
toghether do the job)
Next diagram expresses the power of the
product that resulted from this solution:
Things
that this diagram doesn't show about the resulted product:
- it works
online and offline.
- doesn't use eval
- detects and shows the files
that form circular dependencies.
Now we can say that the challenges
established in the first part were finally met.
Notes:
- the latest version of this implementation
can be found at IncludingEngine.jsFramework.com
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||