I have such code:
A.js
module.exports = function() {
/*
Here I need to find out the path of module in which this function was called.
*/
};
B.js
var A = require('./A.js');
A();
C.js
var A = require('./A.js');
A();
Is it possible to find out from which file function of module A is called? I know that I can pass __filename param:
var A = require('./A.js');
A(__filename);
but maybe there is another way without passing any params to A()?
Well, it is possible, but you really should not do this. You can examine the error stack to get the calling file path like this:
function getCallingFile(n) {
// Regular expression used to extract the file path
var exp = / \(([^:]+)(:[^\)]+)?\)$/;
// Extract line from error stack
var line = new Error().stack.split('\n')[1 + n];
// Try to find path in that line
var m = exp.exec(line);
if(m) {
return m[1];
} else {
return null;
}
}
The parameter n means how many levels of the stack should be skipped, in your example it should be 1.
Why shouldn't you do this? Because
the exact format of err.stack has not been specified formally,
this function will fail if you call it from native code,
it is not what error stacks have been designed for and
it enforces a specific directory which might cause problems if you ever refactor your code.
If I understand your question properly, then the answer is No. A function in Javascript does not know the filename of its caller in any standard way that is documented in a specification. There are some hacks using the exception stack trace, but it is not recommended to use that for a variety of reasons.
You don't explain why you're trying to do this, but in general a function should not change its behavior based on who the caller is. Rather a function should have a defined behavior based on the arguments passed to it. If you want a different behavior when called from B.js and from C.js, then you should specify some argument when calling it in each circumstance that indicates what the behavior should be or create different functions that can be called to generate the different behaviors.
Related
To run a simple Javascript program using v8 I go about it as follows:
// Create a string containing the JavaScript source code.
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, "'Hello' + ', from Javascript!'", v8::NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
How can I go about calling a Javascript function in a /path/to/my_js_functions.js file?
function myJsFunction(stringParam) {
return stringParam // The function returns a stringParam from the parameter
}
Thank you all in advance.
First you have to get your hands on the function object. Assuming it's in the global scope (== on the global object), you can access it like this:
v8::Local<v8::String> name = v8::String::NewFromUtf8(
isolate, "myJsFunction", v8::NewStringType::kInternalized).ToLocalChecked();
v8::Local<v8::Value> obj =
context->Global()->Get(context.local(), name).ToLocalChecked();
if (!obj->IsFunction()) {
/* someone overwrote it, handle error */
}
v8::Local<v8::Function> my_function = v8::Local<v8::Function>::Cast(obj);
Note that every time you get a MaybeLocal, the result could be empty, which happens when an exception was thrown. If you can't guarantee that that won't happen, then you shouldn't just use .ToLocalChecked() (which will crash when the MaybeLocal is empty), but instead properly check for and handle the error case.
Once you have a function, you can prepare arguments for it and call it:
v8::Local<v8::Value> receiver = ...;
int argc = ...;
v8::Local<v8::Value> args[argc] = ...;
v8::MaybeLocal<v8::Value> result = my_function->Call(context.local(), receiver, argc, args);
Again, the result is a MaybeLocal, because functions can throw exceptions (explicitly, or indirectly by calling/doing something that throws). It's up to you to catch any error cases, and otherwise Cast the result to the appropriate type and do something with it.
(Working with JavaScript through a C++ API is not exactly pleasant. That's largely due to the many conceptual differences between the two languages.)
For many more examples, have a look at V8's test-api.cc.
I have a hard time following along with the provided instructions. I'm unclear on references made to which file is the module, and which file is the "original program file," which is "your program" and similar.
I can find solutions to this exercise, and I vaguely understand how/why they are solutions, but when I try to build from scratch I have a hard time following along with the provided instructions. I'm unclear on references made to which file is the module, and which file is the "original program file."
My question is: will someone please clarify these instructions for me? Secondly, I'd like to know if it is possible to solve this problem with all of the module import statements in one file -- maybe the "main.js" file? (As opposed to having the fs and path imports within the MAKE IT MODULAR module.) Also, is it possible to console.log from the module file, so that in the main.js file you only have to call the module function with parameters in order to log the filtered results?
I can see scope rules requiring file-specific imports, but am interested to learn what is required or possible.
This lesson begins by referencing the solution to the previous exercise, which is a js file which imports fs and path and defines a function which does a file sort by file extension within a specified directory. The directory name and file extension string are taken as arguments.
MAKE IT MODULAR asks to expand upon the previous answer by putting the sort function into a module and using that module to deliver the same sort results.
Here is my solution to the previous exercise. I understand that I will have to move the "." concat to another function per this exercise's requirements. I also understand I could have used a .forEach method, as was used in the official solution, included below.
var fs = require('fs');
var path = require('path');
var fileType = "." + process.argv[3]
fs.readdir(process.argv[2], function (err, list) {
for (i = 0; i < list.length; i++) {
if (path.extname(list[i]) === fileType) {
console.log(list[i]);
}
}
});
Official:
var folder = process.argv[2]
var ext = '.' + process.argv[3]
fs.readdir(folder, function (err, files) {
if (err) return console.error(err)
files.forEach(function (file) {
if (path.extname(file) === ext) {
console.log(file)
}
})
})
Here is the exercise:
This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this.
Create a program that prints a list of files in a given directory, filtered by the extension of the files. The first argument is the directory name and the second argument is the extension filter. Print the list of files (one file per line) to the console. You must use asynchronous I/O.
This "program" is the file from the previous exercise, with two arguments, correct?
You must write a module file to do most of the work. The module must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in that order. The filename extension argument must be the same as what was passed to your program. Don't turn it into a RegExp or prefix with "." or do anything except pass it to your module where you can do what you need to make your filter work.
This "module file" is the same as referenced in the previous paragraph ("program"), correct? The module file exports the function, which is the file which is imported to something like main.js?
The filename extension argument must be the same as what was passed to your program.
But if the "original program" is the one with the function with two arguments how can the same file be the one with the function with three arguments? And a reference to "that was passed to your program" makes it sound like the "other" file is the program file?
The callback function must be called using the idiomatic node(err, data) convention. This convention stipulates that unless there's an error, the first argument passed to the callback will be null, and the second will be your data. In this exercise, the data will be your filtered list of files, as an Array. If you receive an error, e.g. from your call to fs.readdir(), the callback must be called with the error, and only the error, as the first argument.
My understanding is that both files have callback functions, so I think I'll have to error handle both files.
You must not print directly to the console from your module file, only from your original program.
In the case of an error bubbling up to your original program file, simply check for it and print an informative message to the console.
OK, now I'm really confused... The "original program" IS the "module file", isn't it? As in the "module file" is the one that exports, and is then imported into something like main.js, or a main "program" file, but not the "Original" program, the one that was created in the previous exercise?
And lastly:
These four things are the contract that your module must follow.
Export a single function that takes exactly the arguments described.
Call the callback exactly once with an error or some data as described.
Don't change anything else, like global variables or stdout.
Handle all the errors that may occur and pass them to the callback.
The benefit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work.
I expect the "module" file to be the "original program" file, with a function with 2 arguments exported, which is imported to a "main program" file with a function with 3 arguments, which prints to the console.
Please help me reconcile the terminology I have in my mental model with the terminology specified in the wording of this lesson. Thank you.
This "program" is the file from the previous exercise, with two arguments, correct?
Yes, you can keep the file from the previous exercise, but edit it. It's still a program that will take two command line arguments, yes. Let's call this file main.js.
This "module file" is the same as referenced in the previous paragraph ("program"), correct?
No. It's a new, separate file. Let's call it filesHelper.js. It's a module that will be imported by the main module ("the program").
The new file will contain much of the code that the program from the previous exercise did contain, yes. You should move it from the main.js into the filesHelper.js, inside that function that the module will export.
The module file exports the function, which is the file which is imported to something like main.js?
Yes. The filesHelper.js module file will declare and export the function, the main.js file will import and call the function. So the code you previously had will now be distributed to the files as following:
// main.js
… // require the filesHelper
… process.argv[2], process.argv[3] … // a function call with a callback
… // error handling
for (… i = 0; i < ….length; i++) { // don't forget to declare the index variable
console.log(list[i]);
}
});
// filesHelper.js
var fs = require('fs');
var path = require('path');
… // a function declaration with three parameters
fs.readdir(process.argv[2], function (err, list) {
… // error handling (delegate to the callback)
…
for (… i = 0; i < list.length; i++) {
if (path.extname(list[i]) === fileType) {
… // build the result array
}
}
… // call the callback with the result
});
… // export the function
Fill in the blanks :-)
I'd like to know if it is possible to solve this problem with all of the module import statements in one file -- maybe the main.js file? (As opposed to having the fs and path imports within the filesHelper.js module.)
Yes, it's kinda possible, but it becomes absolutely unwieldy quickly. This is called "dependency injection", and you'd do it by giving your exported function 5 parameters not only 3, so that you can pass in the fs and path as extra arguments, and don't need to import them in the filesHelper any more.
The downside of this approach is that usual modules have more than just two imports, and having to pass dozens of them to every function from another module that you call is not maintainable. Also, your main.js would need to do all the imports, would need to know about the dependency details of every single module you wrote, and quickly become a god module.
So unless you actually have an application use case to use the same module multiple times with different dependencies, go for the normal declarative module import style.
Is it possible to console.log from the module file, so that in the main.js file you only have to call the module function with parameters in order to log the filtered results?
Yes, it's possible for sure, but then it is no longer modular. The key point to modularity - apart from separation of concerns - is reusability.
Say you had another program, main2, that wanted to read all files with a certain extension from a certain directory, and then send their contents to a printer? You couldn't use the filesHelper for this if you had hardcoded the file name logging, but you can when you have a generic callback that is called with an array of results.
After a few days of research, and using Bergi's clarifying answer above, I've re-authored the question in a way that is perhaps more clear. I still don't think I would have been able to answer this within the context of the learnyounode tutorial, as this exercise introduces numerous concepts that weren't yet made clear in previous exercises, namely the division of logic between the callback placeholder variable name parameter in the module and the callback function definition within the actual parameter being specified as an argument when the function is called.
This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this: main.js and filesHelper.js.
The high-level requirements of this lesson are the same as the previous: create a program that prints a list of files in a given directory, filtered by the extension of the files. The first command line argument is the directory name and the second argument is the extension filter. Print the list of files (one file per line) to the console. You must use asynchronous I/O.
You must write a fileHelper.js file to do most of the work. This file is the module file, and will contain much of the code from your solution to the previous exercise. The main difference is the module file must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in that order. The filename extension argument must be the same as what will be passed to your program via the command line arguments. Don't turn it into a RegExp or prefix with "." or do anything except pass it to your module where you can do what you need to make your filter function work.
To define a single function export, you assign your function to the module.exports object within filesHelper.js, thus overwriting any value which is already there:
module.exports = function (args) { /* ... */ }
Or you can use a named function and assign the name.
function filterFn(args) { /* ... */ }
module.exports = filterFn
To use your new module within main.js, use the require() call in the same way that you require('fs') to load the fs module. The only difference is that for local modules must be prefixed with './'. So, if your file is named mymodule.js then:
var mymodule = require('./mymodule.js')
The '.js' is optional here and you will often see it omitted. You now have the module.exports object in your module assigned to the mymodule variable within main.js. Since you are exporting a single function, mymodule is a function you can call!
The third argument of the module (the callback function) will not have a function definition within the exported module function, but rather will have to be defined when provided as an actual parameter when the module function is being called from the main.js program file. (i.e. when calling the function from main.js, the 3 arguments will be file directory, file type filter, and "function (err, data) {/* … */}".) However, instructions for how errors or data should be handled by the callback function will be required within the exported function.
In other words, the details of the "callback" argument/function are shared between the main function and the module function. Instructions within the exported function are responsible for returning either an error message, or the filtered list of files by specifying how callback will be called, either with only one argument in case of an error (callback(err)), or with the first argument null and the second containing the filtered file list as an array (callback(null, list)), while the actual function definition is to be specified when entering actual arguments to the program via main.js.
Example:
function bar (callback) {
foo(function (err, data) {
if (err)
return callback(err) // early return
// ... no error, continue doing cool things with `data`
// all went well, call callback with `null` for the error argument
callback(null, data)
})
}
Furthermore, the callback function, when defined as an actual parameter in main.js, must be called using the idiomatic node(err, data) convention, and in the case of an error bubbling up to your main.js file, simply check for it and print an informative message to the console.
You must not print directly to the console from your module file, only from main.js.
These four things are the contract that your module must follow.
Export a single function that takes exactly the arguments described.
Call the callback exactly once with either an error or some data as described.
Don't change anything else, like global variables or stdout.
Handle all the errors that may occur and pass them to the callback.
The benefit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work.
Here is my code which passed the tests:
//filesHelper.js
var path = require('path')
var fs = require('fs')
module.exports = function (directory, filterString, callbackFunction) {
fs.readdir(directory, function (err, list) {
if (err) {
return callbackFunction(err)
} else {
var filteredList = []
for (let i = 0; i < list.length; i++) {
if (path.extname(list[i]) === "." + filterString) {
filteredList.push(list[i])
}
}
}
callbackFunction(null, filteredList)
})
}
...
//main.js
var myModule = require('./filesHelper.js')
var directory = process.argv[2]
var filterString = process.argv[3]
myModule(directory, filterString, function (err, data) {
if (err) {
console.log('There was an error: ', err)
} else {
for (const file of data) console.log(file)
}
})
I have a simple javascript error logging mechanism in place and it looks somewhhat like this:
window.onerror = function (ErrorMsg, Url, LineNumber, Col, Error) {
// ajax these to the server, including Error.stack}
The problem is that I'd also like to get the value of the local variables and function parameters when the error occurred. Is this even possible?
I'm thinking about modifying the Function prototype so that each time a function runs, its arguments are stored in a global array of strings and then the error handler would just add this array to the ajax call. Can JavaScript do this?
#1 Can local scope be recovered in onerror() without black magic?
Without this being bound in the scope of window.onerror() or the surrounding variables being directly accessible, it's impossible to regain access to the variables you had set.
What you're mostly wanting access to is this.arguments or arguments or the equivalent, but that's destroyed. Any hope of obtaining a key-value associative array or hash-like object would involve meta-programming ( i.e. reading the function definition to obtain the variable names, and obtaining an exception report to attempt to salvage data ).
See this answer for more on something similar:
Getting All Variables In Scope
But this "lacking functionality" is a good thing:
If you could gain access to what you're asking for, that would likely be a fault in the Javascript engine. Why? Because the variable states and contents themselves are what caused the exception/error, assuming bad code wasn't the issue to begin with.
In other words, if you could get access to a faulty variable, that might be a door into an infinite loop:
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Etc.
#2 Can Javascript store all arguments of every function call by voodoo?
Yes. It can. This is probably a really bad idea ( see #1 ) but it is possible. Here is a pointer on where to start:
Is there a way to wrap all JavaScript methods with a function?
From there, what you're wanting to do is push this.arguments or equivalent to a stack of function calls. But again, this is approaching insanity for many reasons. Not the least of which is the need to duplicate all the values, lest you reference mutated variables, or be unable to access the data at all... and like I said above, the problem of bad data in general. But still, it is possible.
Is this even possible?
No. A stack trace is proof that the stack has unwound, all stack frames and all the local variables they contained are gone. As for getting the name of a variable, that is not even possible at run time.
To start off i accept #Tomalak completely.
I was also put in your situation where i needed to debug a remote running app in case of crash.
As a work around I have forked my code for you in a fiddler. Please modify according to your need.
Caveat: You have to wrap the function body with try{..}catch(e){..} as illustrated in the fiddler code.
Please read the inline comments for understanding.
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
console.log(errorObj);
}
window.addEventListener("reportOnError", function(e){
console.log(e.detail);
/*Send to the server or any listeners for analysis.*/
//Http.send(e.detail);
});
function ExceptionReport(ex, args, scope) {
var self = {};
self.message = ex.message;
self.stack = ex.stack;
self.name = ex.name;
self.whoCalled = args.callee.caller.name == "" ? "Window": args.callee.caller.name;
self.errorInFunction = args.callee.name;
self.instanceOf = scope.constructor;
self.KeyPairValues = getParamNames(arguments.callee.caller.toString(), Array.prototype.slice.call(args)); //Contains the parameters value set during runtime
window.dispatchEvent(new CustomEvent('reportOnError', {'detail':self}));
}
//Utilties
function getParamNames(fnBody, values) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,
ARGUMENT_NAMES = /([^\s,]+)/g,
result = fnBody.slice(fnBody.indexOf('(')+1, fnBody.indexOf(')')).match(ARGUMENT_NAMES),
obj={};
fnBody.replace(STRIP_COMMENTS, '');
if(result !== null){
for(var i=0; i < result.length; i++){
obj[result[i]] = values.length !==0 ? values[i] : null;
}
}else{
obj = null;
}
return obj;
}
/*
This is a testing/sample function that throws the error
*/
function testing(a,b,c){
try{
dummy(1,2) ; //This line throws the error as reference error.
}catch(e){
ExceptionReport(e, arguments, this);
}
}
//Class Emulation: For instanceof illustration.
function testingClass(){
this.testing = testing;
}
//Named self executing function: This calls the function
var myvar = (function myvar(){
testing(1,2,3);
})();
//Illustrating instanceof in exception
var myVar2 = new testingClass();
myVar2.testing(1,2,3);
//Calling from global scope this is Window
testing(1,2,3);
//Without variables
testing();
I have used examples to illustrate the behavior of functions called in different circumstances.
Below signifies the varialble used for
self.KeyPairValues : Used to store the function parameter set/passed during runtime
self.errorInFunction : This stores the name of the function error was caused in.
self.whoCalled : This stores the function name that invoked the defective function
self.instanceOf : This stores the name of the instance is called creating a new instance.
Other variables are same as in Error object
The others answers here are spot on, but I might be able to offer a suggestion for a slightly different way to accomplish this. Instead of trying to track all scope in your program, why not add a tagging function that tracks the scope of one function's parameters without affecting the runtime of the function. For for example:
var globalRecord = {};
function record(name, fn) {
return function () {
var args = [].slice.call(arguments);
var record = globalRecord[name] = {
args: args,
arg: {}
};
args.unshift(function (name, value) {
return record[name] = value;
});
fn.apply(args, arguments);
}
}
// Then, you track variables like this
var func = record("func", function (record, a, b, c) {
record("a", a); // named parameters are accessible now
record("b", b); // if some error occurs in the function body
return a + b + c;
});
// Calling func still behaves as before.
func(1, 2, 3);
// Errors handled like this:
window.onerror = function () {
globalRecord.func.args; // ==> last set of arguments past to function
globalRecord.func.arg.a; // specific arguments recorded with names
};
You could even use this method to track scope without using a function by anonymously calling the recorded function.
record("test", function (record) {
var a = record("a", /* whatever */);
var b = record("b", /* ... */ );
// do scope specific stuff that might fail
})();
Of course, this isn't a polished implementation by any stretch, but with a little work, I think you might be able to get the behavior you're looking for without any seriously black magic. By selectively adding and removing record calls as the need presents itself, you can have precise control over what is logged without any intrusive hacks.
You can find your answer in this link.
Before taking bundles from the server, you must modify them. For example, to solve your problem, you can do changes in the mentioned link as follows. In the BuildBundleContent Class make this change:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, this){1}",
errVariable, hasContent ? ";" : ""));
If in the modules you have to use something like:
var self = this;
You can use:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, self ? self : this){1}",
errVariable, hasContent ? ";" : ""));
And in added js file:
"use strict";
var customErrorLogging = function (ex, module) {
console.log(module);
//do something...
};
I hope help you.
In my main.js, I am reading a file asynchronously. Once my file is loaded, I set some objects in GLOBAL namespace and use them in my required modules (using GLOBAL namespace or not is a different story, I am using it anyway).
My required module immediately expects that variable to exist at the time of loading. So how do I make it wait till my file reading is complete in the main.js? Do I simply require module in the callback of readFile? Or there's a better way to do it?
example:
fs.readFile('./file', function (data) {
// do something
GLOBAL.obj = data;
});
require('./module.js');
module.js
obj.someFunction();
Your gut feeling of disliking that solution is understandable. (Your stomach is right). The proper way of cleaning this up (and you should take the time – future-you will thank you for it):
go through every one of your ten modules
for each one go through all the functions it exports
for each function figure out, what globals they actually depend on.
add those as arguments to the function.
if they take a lot of arguments now, consider grouping them into objects, creating useful models.
if a bunch of functions all depend on the same set of variables, you can also consider creating a factory function
create a function that takes the formerly global variables as arguments and wrap all of the module's code into that function.
make that function the single export of your module. It serves as a factory function and creates the context for all the other functions in that module. It should return whatever the module exported before.
Example
// DB used to be a global
module.exports = function(DB) {
function getUser(user, cb) {
DB.get('user', db);
}
return {getUser: getUser};
};
You can then use it like this:
var module = require('module')(DB);
module.getUser(myUser, function(){}};
Yes, just follow the rule #1 of async programming. Stuff that depends on callback happening must be executed in that callback. Since your require depends on the variable set in async, you can only use your require inside it:
fs.readFile('./file', function (data) {
// do something
GLOBAL.obj = data;
require('./module.js');
});
Let's assume I have an AMD module that conditionally requires a second module in some environments:
define(["require"], function(require) {
var myObj = {
foo: console.error.bind(console)
};
if(browserEnv)
require(["./conditional-polyfill"],function(polyfill){
myObj.foo = console.log.bind(console,polyfill) ;
});
return myObj; //returns before conditional require is satisfied
});
The question is: How can I delay the define() call to return/callback AFTER the conditional require has been completed?
I.e. the code below fails:
require(["module-from-above"],function(logger){
logger.foo("Hello!"); //console.error gets called
});
My thoughts on solutions to this issue:
If I inline ./polyfill, everything would work. However, that just circumvents the problem and doesn't work for every case. I want it modularized for a reason.
I could return a Deferred object instead of myObj that gets fulfilled by ./conditional-polyfill later. This would work, but it's really ugly to call loggerDeferred.then(function(logger){ ... }); all the time.
I could make a AMD loader plugin for this module. And call the callback as soon as everything is ready. Again, this would work, but own loader plugins don't work with my build tool.
All solutions I can think of are more hacks than good code. However, I think that my issue isn't too far-fetched. So, how to handle this?
Push conditional outside of "factory function" (the name commonly used in AMD community to refer to the require's and define's callback function)
;(function() {
function factory(require, polyfill){
var myObj = {
foo: console.error.bind(console)
}
if(polyfill){
myObj.foo = console.log.bind(console, polyfill)
}
return myObj
}
var need = ['require']
if(browserEnv){
need.push("./conditional-polyfill")
}
define(need, factory)
})();
I would use a Deferred, as you say.
The deferred pattern is the ideal solution to this kind of issue, because it allows you to tie complex async operations together in a consistent way.
It will make your code a bit larger, but its a simple solution compared to modifying the loader and the build tools.