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.
Related
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.
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.
To make debugging easier, I'm capturing all of the console logs in Chrome so that users who submit a feedback entry will also submit all of the logs to our server. When someone encounters a problem in production, I can first and foremost get them back to work so that I can then sit down and more thoroughly go through all of the logs to determine the root cause of whatever issue the user encountered in production.
The technique I use to capture the logs involves overriding console.log so that all text entered in the first argument gets stored in an array while simultaneously invoking the legacy function so that I can still see the logs in the console too.
The problem is when there's the occasional uncaught exception. These aren't included in the uploaded logs, so it's not always clear what caused the problem. So I tried overriding ReferenceError by writing a JavaScript function that takes a function as an argument, then returns a new function that does stuff with it, like storing data in a variable, and then invoking the legacy function as the last step:
function overrideException(legacyFn) {
/** arguments for original fn **/
return function() {
var args = [];
args[0] = arguments[0];
// pass in as arguments to original function and store result to
// prove we overrode the ReferenceError
output = ">> " + legacyFn.apply(this, args).stack;
return legacyFn.apply(this, arguments);
}
}
To test the overrideException function, I ran the following code on the console:
ReferenceError = overrideException(ReferenceError);
Afterwards, I tested the returned function, the new ReferenceError, by manually throwing a ReferenceError:
throw new ReferenceError("YES!! IT WORKS! HAHAHA!");
The resulting output on the console is:
ReferenceError: YES!! IT WORKS! HAHAHA!
And checking the global variable output from the overrideException function shows that it did indeed run:
output
">> ReferenceError: YES!! IT WORKS! HAHAHA!
at ReferenceError (<anonymous>)
at new <anonymous> (<anonymous>:18:35)
at <anonymous>:2:7
at Object.InjectedScript._evaluateOn (<anonymous>:562:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:521:52)
at Object.InjectedScript.evaluate (<anonymous>:440:21)"
Now, here's where things start to fall apart. In our code, we're not going to know when an uncaught exception occurs, so I tested it by attempting to run a function that doesn't exist:
ttt();
Which results in:
ReferenceError: ttt is not defined
However, unlike the case where we explicitly throw an error, in this case, the function doesn't fire, and we're left with only the legacy functionality. The contents of the variable output is the same as in the first test.
So the question seems to be this: How do we override the ReferenceError functionality that the JavaScript engine uses to throw errors so that it's the same one we use when we throw a ReferenceError?
Keep in mind that my problem is limited only to Chrome at this time; I'm building a Chrome Packaged app.
I have done quite a bit of research for the same reason: I wanted to log errors and report them.
"Overriding" a native type (whether ReferenceError, String, or Array) is not possible.
Chrome binds these before any Javascript is run, so redefining window.ReferenceError has no effect.
You can extend ReferenceError with something like ReferenceError.prototype.extension = function() { return 0; }, or even override toString (for consistency, try it on the page, not the Dev Tools).
That doesn't help you much.
But not to worry....
(1) Use window.onerror to get file name, 1-indexed line number, and 0-indexed position of uncaught errors, as well as the error itself.
var errorData = [];
onerror = function(message, file, line, position, error) {
errorData.push({message:message, file:file, line:line, position:position, error:error});
};
See the fiddle for an example. Since the OP was Chrome-specific, this has only been tested to work in Chrome.
(2) Because of improvements to (1), this is no longer necessary, but I leave this second technique here for completeness, and since onerror is not guaranteed to work for all errors on all browsers. You will also sometimes see the following:
var errors = [];
function protectedFunction(f) {
return function() {
try {
f.apply(this, arguments);
} catch(e) {
errors.push(e);
throw e;
}
};
}
setTimeout = protectedFunction(setTimeout);
setInterval = protectedFunction(setInterval);
etc...
FYI, all this is very similar to what has been done in the Google Closure Compiler library, in goog.debug, created during Gmail development with the intent of doing exactly this. Of particular interest is goog.debug.ErrorHandler and goog.debug.ErrorReporter.
I am writing asynchronous module, but I can not pass an array structure. Please help. That's the error appears. How to avoid it?
error C2440: '=' : cannot convert from 'v8::Handle' to 'v8::Array *'
struct Async {
Handle<v8::Array> result;
}
void wmiWorker(uv_work_t* req) {
Async* request = (Async*)req->data;
*(request->result) = getArray(1);
}
Handle<Array> getArray(int x) {
HandleScope handle_scope;
Handle<Array> array = Array::New(3);
if (array.IsEmpty())
return Handle<Array>();
array->Set(0, Integer::New(x));
return handle_scope.Close(array);
}
Your line
*(request->result) = getArray(1);
assigns a Handle<Array> to *(Handle<Array>) (which means Array*), which is not valid.
However even with that, there is an important factor that you are not taking into account. Your wmiWorker function is running in a separate thread. NodeJS and V8 only allow a single thread of execution for JS, and what you are attempting to do is create a JS array inside of a separate thread.
Instead you will need to create a vector or something, and generate the V8 array from that inside of the work callback's after_work callback.
I'm working my way through the Eloquent JavaScript Book and in it there is the following code:
function createFunction(){
var local = 100;
return function(){return local;};
}
When I run this via the node console (run node from command prompt) by calling createFunction(), I get [Function] as a returned value. However, according to the book I should get 100.
So my two questions: Why is this? and Second, is running these little examples in the node console a bad idea for testing JS code?
You need to call the response of createFunction().
createFunction()();
The first invocation (()) calls createFunction() and returns the inner function, which the second invocation executes and returns the local variable which was closed over.
Running small examples in a node console (or any other) is fine, so long as you know the environment, e.g. a browser's console is generally eval()'d, which can create side effects, such as how delete can apparently delete variables, not just object properties.
You get 100 by invoking the return value of createFunction, which is itself a function.
createFunction()();
...or perhaps more clearly...
var new_func = createFunction();
new_func();
function createFunction(){
var local = 100;
// v---v-----------------------v return a function from createFunction
return function(){return local;};
}
// v------- the returned function is assigned to the new_func variable
var new_func = createFunction();
// v------- the returned function is invoked
new_func();
For those that have a similar problem, I completely missed the double () so the call looks like createFunction()().