Intro
I'm programming a project where C# and JavaScript code need to work together, so I decided to use CefSharp as it guarantees the latest JS features (in contrast with WebView).
The Goal
Now I need to create an async C# method which would call an async JS function and then wait for it to finish. The problem is that JavaScript doesn't have anything like the await keyword, so everything is defined in terms of events.
This is what the Javascript code looks like:
var name1 = "A";
var name2 = "B";
library.renameObject("A","B");
library.onrename = function(from, to){
if(from === "A"){
//let C# know
}
}
And the C# code should ideally be something like this:
class FooObject
{
string Name;
async Task Rename(string newName)
{
await mainFrame.EvaluateScriptAsync(#"
//The JS code
");
Name = newName;
}
}
The Problem
At first I thought using a task/promise would do the job, but after some testing I found out that it's impossible to pass objects between JS and C#.
This means that when I tried to pass TaskCompletionSource to an IJavascriptCallback, I got
System.NotSupportedException: Complex types cannot be serialized to Cef lists
Then I tried to return a Promise from the JavaScript code, but in C# I always got null.
A Bad Solution
I'm aware that using reflection, proxies and Dictionary<int, WeakRef<object>> I could provide an interface, so that any C# object could be accessed from JavaScript in a way that would be indistinguishable from using an actual JS object. The approach would be:
save (a weakref to) the C# object in the dictionary under a unique key
using Reflection create methods that take the unique key as an argument and allow reading fields and calling methods of the object
expose these methods to JavaScript using RegisterJsObject
create a Proxy that would mimic an ordinary JS object and call the exposed C# methods in the background.
The bad news with this solution is that in JavaScript there are no destructors/finalizers, so I have no control over the V8 GC. This means the C# objects would stay there forever (memory leak) or get collected by the .Net GC too early (null pointer exception).
Related
I have noticed that if I write a method that only acts on local variables of calling methods (does not directly interact with a class variable) then I get a warning that the method can be static.
Sometimes it's nice to abstract a large piece of code into a separate method. Is this somehow consider bad practice in JavaScript/TypeScript?
Since I keep getting these warnings I'm taking a chance that the post police will pounce on me for asking a question that could invite opinions. Let me defend against that by saying that the warnings I'm getting are not opinions. They are definite warnings. That suggests that there exists an answer that is not opinion, at least from the perspective of the people who decided to create those warnings.
EDIT:
I was asked to put code here to provide a valid reason as to why I would want to do this. I personally don't think this adds any clarity to question I asked but here's an example of a method that was producing the warning in WebStorm.
//Change object array in *.content objects to values array
//noinspection JSMethodCanBeStatic
transformData(visibleData) {
const ret: any = {};
ret.headings = visibleData.headings;
ret.checkbox = this.checkBox; //add if the table needs checkboxes
ret.content = [];
for (let i = 0; i < visibleData.content.length; i++) {
ret.content.push(_.values(visibleData.content[i]));
}
return ret;
}
The point of this function is to take a clone of the instance, so as not to modify the instance itself, and create a different object, mainly a values only array, which will be used to databind in the template. I did this so my table template could be reusable since columns vary in number.
Code which does not interact with instance should be a free function or at least a static method of a class when you believe it is tightly coupled with class API.
Every additional method you add to API has to be supported. So larger classes require more support than smaller classes. In some languages, like Java, you can't have free function, so you have to attach function to some class, but TypeScript and JS are more flexible, so there is no need to pollute class API.
And you could consider it from the performance optimization point of view.
When JS evaluates class method it looks it up in the object instance, than in the object prototype, than in the parent's prototype, etc. Every lookup eats cpu time, so when you think about performance, free function is your choice.
I want to be able to define a statement in javascript. For example, I want to define
a statement called file that works like a class.
function file() {
//code goes here
}
I want that to be used as a statement, like if,for,andreturn.
file filename(filename,purpose) {
//code goes here
}
Do I need to build a seperate compiler or is it possible?
Please change the title if there is a better way to say it.
What are you trying to accomplish?
You can emulate some class-like structure in JavaScript using the Revealing Module Pattern
Also, I've never seen a class work like what you've described -- typically you instantiate an object of a class, and then access the object's public properties. This can be done in JavaScript ('cept objects are created dynamically). For example:
// file 'class'
var file = function () {
var a; // private variable
function filename(name, purpose) {
// code goes here
}
// return public members
return {
filename: filename
};
};
// An object created from your 'class' with the member function 'filename()'
var aFile = file();
Then call your member function using the . operator, like so: aFile.filename(name, purpose);
This would be writing a new language based on Javascript, much like Coffeescript, among many others. Those languages need to compile to JS before being served to a web browser, for instance.
Take a look at a Coffeescript -> JS interpreter to know how to go about this. For the record, I don't think this is a good approach.
Lastly I'll note that languages like Scala have very good DSL support, meaning it's easy to add features within the language. For instance, even + in Scala is library code, not native code. (More technically, could be written that way from a language standpoint.)
I want to be able to define a statement in javascript.
I want that to be used as a statement, like if,for,andreturn.
No, you cannot do this, as a Javascript parser would not be able to parse this.
If you really wish to do this, your only option would be to create your own language, and write a transpiler from your new language to Javascript, as #djechlin has pointed out.
I believe what you want is to implement control structures rather than statements since the example you gave, if, for and return are control structures. If that is what you really mean then yes, you can do that with functions but not with the syntax you describe.
In javascript, functions are first class objects. That is, they can be assigned to variables and passed as arguments to other functions. For example, here's an implementation of if that uses no built-in control structure (no if, while, switch etc. and no ternary operator):
function IF (condition, callback) {
[function(){}, callback][+!!condition]();
}
You can use the above function as a replacement of if but the syntax is a bit unconventional:
IF ( a == b, function(){
console.log('hello');
});
But if you've been programming javascript long enough the above syntax would be familiar and you'd have encountered many similar control structures implemented as functions such as [].forEach() and setTimeout().
So, if you want to implement a control structure to parse a file for example, you can do something like this:
function parseFile (filename, callback) {
// code to process filename
callback(result);
}
Or even something like this:
function eachLine (filename, callback) {
// code to process filename
for (var i=0; i<file_content.length; i++) {
callback(file_content[i]);
}
}
which you can use like this:
eachLine("some_file.txt",function(line){
if (line.match(/hello/)) {
console.log('Found hello! This file is friendly.');
}
});
if you don't need parameters you can do:
Object.defineProperty(window, 'newcmd', {
get: () => console.log("hello")
})
newcmd
I want to call a method in flex from javascript side,
so that I can retrieve javascript object which contains data in flex.
now I'm trying like
var result:Object = new Object()
var keyset:Array = data.getKeySet();
for (var i:int = 0 ; i < keyset.length ; i++) {
result[keyset[i]] = data.get(keyset[i]);
}
return result;
but it do not work. how can I make it right?
p.s. I know it is fundamental question, but I couldn't find anything even though I googled for an hour. So please help!
To communicate between Flash/Flex and JS on the page, use the ExternalInterface class. You can't directly pass objects, but you can convert your object into a serialisable/string. Here's how you'd call a function called 'myFunc' and set it two arguments, a string and a number:
ExternalInterface.call('myFunc',1,'aString');
After the function name, which must always be a string, there is a ...rest parameter. Simply enough, this means you can send any number of arguments to the function, separating them with commas (we do two here).
If you used AS2 at any point in the past you may know the 'eval' function, this was inherited from (and is thus still used by) JS - it analyses a string and attempts to parse it into JavaScript, using this you can literally send Javascript code instead of a func/args:
ExternalInterface.call('alert("Hello!")');
If you want two-way communication, use the ExternalInterface.addCallBack function to register a function as callable from JS.
In case of errors when doing this, you may need to adjust your embed code: "In the object tag for the SWF file in the containing HTML page, set the following parameter:
param name="allowScriptAccess" value="always"
I believe you cannot call a method in AS3 from JS directly (and vice-versa). There should be an interface for it though, where one can call the other. If i remember correctly, you should use the ExternalInterface API.
Also, you can't pass Flex objects to JS (and vice-versa) also. Try building a generic object that is serializable to JSON and use that serialized data in passing data to each other. The receiving party can parse it back to use the data. In this example, the code passed a string from JS to AS3.
In your case, the Flex function would:
build an object
stuff it with data
serialize it into a JSON string
return the string to the caller
Then when JS calls the function:
JS receives the string
Use JSON.parse() to reconstruct the JSON string into a JS object
use the object
A lot of people (like me) are used to JavaScript in the respect that code is executed in the order of loading, i.e. from top to bottom, so if an element hasn't yet loaded it is impossible to manipulate it, or if a function has not yet been defined it is impossible to call it. Since JS (and VBscript, but that's not too popular) is the only internet client-side programming (scripting, if you wish) language, and therefore the only language to come across the problem of having to be loaded from a different location, I assume that no other language does that, i.e. one can call a function/method in the language, while having defined it later on in the document. Is this assumption correct, or are there other languages that do that too?
EDIT: for those who don't understand what I mean, here's an example in Java:
public class MainClass {
public static void main(String[] args) {
SomeClass SomeObject = new SomeClass;
SomeObject.changeSomeVariable("someValue");
}
}
class SomeClass {
String someVariable;
void changeSomeVariable(newValue){
someVariable = newValue;
}
}
Note how the class defining the object goes after the line where the object is created. Will the above work (I might have gotten the syntax a bit wrong)?
In C++ (compiled language), for example, you can use a class or a function while you know only its definition, not implementation.
int some_function(int i);
// we know the name of the function, the types of its parameters and
// its return value. We don't know, however, what does this function
// exactly do.
int main() {
int x = some_function(42);
}
Of course, implementation of the function must be placed somewhere, otherwise linking will fail.
But if we don't know the name or the signature of a function or a class, we can't use it. In opposite to compiled languages, in scripting languages (such as Python, PHP, JavaScript etc) you can do it:
function f() {
return some_function(42);
}
This JavaScript function can be created without error even if no some_function is defined. But it must have been defined when f() is called.
We can talk and talk about these facts relative to some languages. But there are a lot of languages, and they all are different. If you're curious about this question, I can advise you to learn several other languages a bit (at least one compiled and one functional).
Many scripting languages such as PHP and Ruby execute in order.
That is a tenant of scripting languages.
someone asked how to get the value of a JSObject property from c. That helped me a bit.
But, does anyone know how to get the current JavaScript name of an object from c?
example:
var foo={prop:'bar'};
then somewhere for example in jsapi.cpp:
JS_somemethod(JSContext *cx, JSObject *obj){
//how do i get the name 'foo' (or the current alias) here if *obj points to the foo (or whatever alias name) object?
}
Thx for hints and answers!
Okay, just to document the question clarification from your comment I'll repeat it here:
Maybe i tell you in short my purpose: For the integration of new security system in webbrowsers i need to find out what is accessed during a common session on a website. my aim is to get something like a log which objects are accessed and how (read,write,execute). for example: window.alert (x) window.foo.bar (w) ... you now why i need the names of the variables? maybe you've got an other idea?
Just to say it up front, this is pretty tricky in general. There are a few options available to you, all of which are somewhat difficult:
Use the debugging API, either via the cool new debugger object API or via jsdbgapi.cpp (the complex and slightly gross interface that firebug uses). You can use debugger functionality to trap on all property accesses, functions calls, and local references in order to dump out interesting properties of objects.
If you're only interested in the way that your (user defined) objects are accessed, you can use Proxies that wrap your objects and dump out the accesses being performed on them. A slightly more powerful and low-level version of proxies are actually used in the browser to implement our security features. (Additionally, most of the proxy functionality is accessible for custom-created objects in the JSAPI via our meta-object-protocol, but proxies are just a much cleaner version of that same functionality.)
Instrument the interpreter loop in jsinterp.cpp. A lot of research-like work turns off the JITs and instruments the interpreter loop, because it's fairly understandable if you've worked on language implementations before. Unfortunately, it's not always easy to translate what you want to do into interpreter loop instrumentation at first, even if you have experience with language implementations.
The debugger object is definitely my favorite option of those I've listed here. If you go with that approach and end up getting stuck feel free to visit #jsapi in irc.mozilla.org and try to get a hold of jorendorff or jimb, they're a) awesome and b) the creators of the debugger object.
Without looking too closely at the API, I'm going to say that while it might be possible to do this in some very basic cases, you don't want to. This is why:
In Javascript, as in most languages, variables point to values. Variables are not the values themselves. The object is not in any way inherently related to the name foo.
For instance, you can do
var foo = {prop: 'bar'};
var fooo = foo;
var foooo = foo;
var quux = {q: foo, r: foo, s: [foo]};
All of those foos are now the exact same foo; which one do you want back? There's no API call for that because it's too ambiguous and not terribly useful.
However, if you really want to find one of the global variables holding a value, you can try iterating over the keys on the global object and testing them for the value.
for(var key in this){
if(this[key] == myval){
var myname = key;
}
}
You'd have to translate this into your API calls or else put it in a function and call that through the API.
The more simple and straightforward solution would be to figure out what you want to do with foo later on, and pass in a callback function that will do that, e.g. with JS_CallFunction.
tl;dr: Previous paragraph.