I am currently a beginner on RequireJS and i am a bit in trouble with the AMD concept, especially the way that RequireJS is defining it.
My aim is to build a smart Loader that call the specific Parser he needs.
To summarize my needs :
(A) I create my loader : new Loader(source)
(B) source represents the data to load. That's a simple string.
(C) A Loader object is created. It executes some algorithm to decide what is the best Parser to use. Eventually, it downloads the parser from a remote location. Finally, it loads the parser dynamically.
My problem is this one : How can I load a module/plugin without expliciting it in the define? I cant set it in the define([theParserHere]) because I am unable to know which Parser is needed.
The require function sounds like it could be used for your purposes. It allows for loading of modules, but not defining a new module.
Your loader could call a function such as the following to load a module dynamically when needed:
function loadParser(name, fn) {
require(["parsers/" + name], fn);
}
name would be the name of the parser or a path or something (note that my path was just an example) and fn is a callback to call when the loading has been completed. The first argument to the function would be the loaded module.
This function could be placed in your loader object or just sit inside the define:
define(function () {
function Loader(text) {
this.text = text;
this.parser = null;
this.loadParser();
}
Loader.prototype.loadParser = function () {
var self = this;
var parserName = this.getParserName();
require(["parsers/" + parserName], function (Parser) {
self.parser = Parser;
self.parse();
});
}
Loader.prototype.getParserName = function () {
//mystery logic to determine language...
return "some-parser-name";
}
Loader.prototype.parse = function () {
if (!this.parser) {
throw "No parser loaded";
}
//do your parsing logic...
}
return Loader;
});
Now, if I were actually doing this, I would use Q or jquery deferreds or something for resolving the parser inside the require callback function instead of all that function calling.
Related
Hi we are building a web app platform where users can make their own smart forms using drag and drop features. We are looking for a way for admin users to create their own custom scripts to run some logic using pre-defined functions for the app. Currently the solution we have come up is using eval().
Knowing Eval is 'evil' we have implemented a function to check if the script is safe before it is executed. Essentially it breaks up the code into tokens and then runs those tokens against a blacklist. Stuff like new, eval, window, require, fetch,browser will show an error. Also the function is executed via a angular service so we try to limit what is injected.
Below is the basic high-level code. We have custom async functions so the solution needs to handle this.
My question is there a better(ie faster) and safer way to run custom scripts?
async runScript(script,callback) {
var updateForm=(id,value)=>{
return this.updateForm(id,value);
}
var getForm=(id)=>{
return this.getForm(id);
}
if (this.checkScriptSafe(script)) {
try {
return eval("(async () => {" + script + "})()");
} catch (e) {
if (e instanceof SyntaxError) {
alert(e.message);
} else {
console.log('Error',e);
alert("Error in script");
}
}
} else {
alert("Script not safe")
}
}
Example script:
"var value = 1 +4; await updateForm("11",value);alert("Success!");"
Function constructor would be a better approach. Function constructor creates a new function that will execute in the global scope. Your eval script (because of the arrow function) will run in the same context as your runScript method. They would access/modify your internals, or override your class methods. They can even override the runScript method itself and remove the checkScriptSafe check.
Using the function constructor is similar to typing in the dev tools console. If your application is not vulnerable to the dev tools console, then you wouldn't have any issues using the function constructor.
Here is an example:
const script = `
var value = 1 +4;\n
await updateForm("11",value);\n
alert("Success!");
`;
// we have to get a handle of the async function constructor
// in order to create an async function
const dummyFunction = async function() {}
const AsyncFunction = dummyFunction.constructor;
// create an async function which will run in the global scope
// the function will have an `updateForm` parameter
const userFunction = new AsyncFunction('updateForm', script);
// now userFunction is equavalent of:
// const userFunction = async function(updateForm) {
// var value = 1 +4;
// await updateForm("11",value);
// alert("Success!");
// }
// bind the current context 'this' to update form and pass it
// to user's function as parameter. The user's function
// will be able to execute it.
userFunction(this.updateForm.bind(this));
I'm not an expert in browser internals. But I assume tokenizing and interpreting the function on your own would be much slower than the Function constructor method. Even if you do everything in the most efficient way, you would still be in the JavaScript domain; v8 (or any other JS engine) would perform the actual interpretation after you. Why not directly give the script to the JS engine then? If the same custom script is going to run frequently, then with the right design, v8 will optimize the custom functions by compiling them into machine code. This wouldn't be the case with eval.
Let me preface this by stating that this needs to be done in pure, vanilla Javascript, with no 3rd-party libraries or frameworks (emphatically not JQuery).
Say I have a JS file, named included_script.js, with the following content:
function sayIt() {
alert("Hello!");
}
Now say I have the following simplified JS function that loads the external JS file and attempts to execute the sayIt function defined therein:
function loadIt() {
var externalScript = document.createElement("script");
externalScript.type = "text/javascript";
externalScript.src = "js/included_script.js";
document.getElementsByTagName("head")[0].appendChild(externalScript);
/* BLOCK HERE, and do not continue until externalScript
(included_script.js) has been completely loaded from the server
and included into the document, so that the following execution of 'sayIt'
actually works as expected. */
sayIt(); /*I expect the "Hello!" alert here, but 'sayIt' is undefined (which
I think - but am not 100% sure - is because this line is reached before
externalScript (included_script.js) is fully downloaded from the server). */
}
Note that before appending externalScript to the head I have tried things like externalScript.setAttribute("defer", "defer"), externalScript.setAttribute("async", "async") (even though I know this is redundant), and et cetera. Note also that callbacks are not feasible for use.
How can I make function loadIt block at the "BLOCK HERE" part shown above until externalScript (included_script.js) is completely downloaded to the client, so that the sayIt function defined in externalScript (included_script.js) actually works when called from function loadIt?
UPDATE BASED ON BOBRODES' BRILLIANT, SIMPLE ANSWER:
included_script.js still has the following content:
function sayIt() {
alert("Hello!");
}
loadIt is now turned into a class (it's a lot more complex than this, but this shows the bare-bones mechanics required for it to work):
function loadIt() {
this.loadExternal = async function() {
return new Promise(
function(resolve, reject) {
try {
var externalScript = document.createElement("script");
externalScript.type = "text/javascript";
externalScript.src = "js/included_script.js";
if (externalScript.readyState) {
externalScript.onreadystatechange = function() {
if (externalScript.readyState == "loaded" ||
externalScript.readyState == "complete") {
externalScript.onreadystatechange = null;
resolve(true);
}
};
} else {
externalScript.onload = function() {
resolve(true);
};
}
document.getElementsByTagName("head")[0].appendChild(externalScript);
}
catch(err) {
reject(err);
}
}
);
}
}
Now, in my main code, I can do the following, with it being guaranteed that function sayIt is loaded and ready for use before it's invoked.
From inside an async function:
var loader = new loadIt();
await loader.loadExternal();
sayIt();
From outside an async function:
var loader = new loadIt();
(async function() {
await loader.loadExternal();
})().catch(err => {
console.error(err);
});
sayIt();
This works beautifully -- exactly what I was after. Thanks, Bob!
As a side note, I know there is a rampant and short-sighted "blocking is always evil in every case imaginable, and can never, ever, under any circumstances, result in anything good" mentality, but I disagree that blocking is bad when a heavily-data-driven GUI is being generated, which depends on multiple custom classes that, in-turn, depend on each other and/or other classes/resources/scripts -- especially when the rendered GUI elements have multiple event handlers (onclick, oninput, onfocus, etc.) that expect the existence/usability of instances of these classes and their methods.
If you can't use callbacks, then use promises, which are designed to create a "blocking" mechanism in an asynchronous environment without having to add a separate callback function.
I am using nodejs and webdriver for automation tests. I am trying to export a function from one js file to another. e.g there is a function called abc under file abc.js and i want to use that function with other file called xyz.js. I tried using export and require but it exports and runs entire test (abc.js) instead of just a function.
//abc.js
console.log('print this');
client= function client() {
driver.get(baseUrl + '/#/login');
};
exports.client = client;
//xyz.js
var client1 = require('abc.js').client();
Requiring a module for the first time causes the module to be cached and it's code to be executed, that's why you're seeing your "print this" log. Next time you call your client function you shouldn't see it.
This is not relevant to the question, but still, in your xyz.js file, since your function isn't returning anything you can use:
require('abc.js').client();
Instead of:
var client1 = require('abc.js').client();
In your abc.js, there's no need for a named function, you can just use:
var client = function() {
...
};
give it a try
function abc(){
console.log('print this');
this.client= function client() {
driver.get(baseUrl + '/#/login');
};
return this;
}
module.exports = abc;
//xyz.js
var abc = require('abc.js')();
abc.client();
its a good practice when capsulating objects in nodejs
I'm rewriting a simple app using HTML/CSS/JavaScript that creates animations with images using intervals, and there's a bunch of buttons that controls these animations.
It's scaling and becoming really messed up, with logic mixed with DOM manipulations via jQuery all through one javascript script file.
So I decided to use the Module design pattern.
Based on my description of the app, is there a problem with this callback implementation for a module?
Or with the module implementation?
In this example, what is the best approach to declare private variables and give access to them through the public api? Getters and setters? Are they really necessary? I want to write readable code but I don't want to over-architect things.
(function($) {
$.Module = function(options){
var module = {
options: $.extend({
callbacks: {
start: false
}
}, options),
start: function(callback){
//console.log('private start method');
if(typeof callback === "function") {
callback();
}
}
}
// public api
return {
start: function(){
//console.log('public start method');
module.start(module.options.callbacks.start);
}
}
}
}($));
var myModule = $.Module({
callbacks: {
start: function(){
console.log('start callback!');
}
}
})
myModule.start();
Here is a sample.
Just because it seems to work to me, and I've seen other implementations that have some code that look like this:
callback: function(method) {
if(typeof method === "function") {
var args = [];
for(var x = 1; x <= arguments.length; x++) {
if(arguments[x]) {
args.push(arguments[x]);
}
}
method.apply(this, args);
}
},
I'm not sure what this last code is supposed to do. Is it intended to return data to the callback function I registered when instantiating the module? If so, how does it work?
Is there a problem with this callback implementation for a module?
Not if this what you want.
Or with the module implementation?
Your instantiation of the options property should probably use a deep extend, the current one is overwriting the complete callbacks object.
I'm not sure what this other code I found is supposed to do. Is it intended to return data to the callback function
Yes. It does support multiple arguments, using the arguments object
… I registered when instantiating the module?
No, it does not have to do with registration. It will call the method that is passed as a parameter to this callback function.
Using this code will release you from the need to do that typeof check every time. You would just write
helper.callback(this.options.callbacks.start, /* optional arguments */)
// instead of
if (typeof this.options.callbacks.start == "function")
this.options.callbacks.start(/* arguments */)
However, until you think that you need this helper you will not need this helper.
I currently have a few large files that I'd like to break up into smaller ones to ease editing. I feel as though these 'code snippets' wouldn't merit being created as a module and/or would have conflicts with scope if made as such.
So instead I'd perfer to just import the contents from these 'clipped' files, into the current execution scope and then eval them. Figured I'd write a helper function to do this(set in the global scope via the 'main' js file.) but I've ran into a snag.
Is there a way to get the calling instance from within the called function.
What I have so far:
global.acquire = (function() {
var cache = {};
var fileReader = require('fs');
return function (file, updateCache) {
var f = require.resolve(file);
if (f) {
if (cache.hasOwnProperty(f) && !updateCache) {
res = cache[f];
} else {
res = fileReader.readFileSync(f, {encoding: "utf8"});
}
cache[f] = res;
// Is there a way to get the calling function's instance so the eval will execute from the caller's scope?
return eval.apply(caller, '(' + res + ')');
} else {
throw "File not found";
}
}
}());
I know I could either pass the instance, or acquire.apply(), but that feels a bit sloppy if I can retrieve the instance from within the function.
There is no way to get at the caller's scope from within a separate function that is external to that scope without either passing in particular variables or using this to set data you want/need to access.