On Github lance / process-bindings
⦿
CodeMash 2015
document.addEventListener("DOMContentLoaded", function(event) { //do work });
if (!isFinite( someVar )) { // to infinity and beyond! }
setTimeout(function() { // pomodoro complete! }, 1,500,000);
var enc = "foo.asp?name=st%C3%A5le&car=saab"; var decoded = decodeURI(enc);
console.log("To be or not to be");
document.addEventListener("DOMContentLoaded", function(event) { //do work });
if (!isFinite( someVar )) { // to infinity and beyond! }
setTimeout(function() { // pomodoro complete! }, 1,500,000);
var enc = "foo.asp?name=st%C3%A5le&car=saab"; var decoded = decodeURI(enc);
console.log("To be or not to be");
document.addEventListener("DOMContentLoaded", function(event) { //do work });
if (!isFinite( someVar )) { // to infinity and beyond! }
setTimeout(function() { // pomodoro complete! }, 1,500,000);
var enc = "foo.asp?name=st%C3%A5le&car=saab"; var decoded = decodeURI(enc);
console.log("To be or not to be");
Asynchronous I/O & Event Loop
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/');
(function(process) { this.global = this; function startup() { var EventEmitter = NativeModule.require('events').EventEmitter; process.__proto__ = Object.create(EventEmitter.prototype, { constructor: { value: process.constructor } }); EventEmitter.call(process); process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated // etc... });
Node.js main function takes a process object
void SetupProcessObject(Environment* env, int argc, const char* const* argv, int exec_argc, const char* const* exec_argv) { Local<Object> process = env->process_object(); // process.version READONLY_PROPERTY(process, "version", FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION)); // process.binding NODE_SET_METHOD(process, "binding", Binding); }
The process object is created in C++ using the V8 API
Some native properties are bound to the object here
static void Binding(const FunctionCallbackInfo<Value>& args) { HandleScope handle_scope(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate()); Local<String> module = args[0]->ToString(); node::Utf8Value module_v(module); Local<Object> cache = env->binding_cache_object(); Local<Object> exports; if (cache->Has(module)) { exports = cache->Get(module)->ToObject(); args.GetReturnValue().Set(exports); return; } // etc. }
Similar to a Javascript module lookup, but with native exports
void Load(Environment* env) { // Compile, execute the src/node.js file. The node.js file returns a function 'f' Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(), "node.js"); Local<Value> f_value = ExecuteString(env, MainSource(env), script_name); Local<Function> f = Local<Function>::Cast(f_value); // Now we call 'f' with the 'process' variable that we've built up with // all our bindings. Inside node.js we'll take care of assigning things to // their places. Local<Object> global = env->context()->Global(); Local<Value> arg = env->process_object(); f->Call(global, 1, &arg); }
Node.js V8 layer loads lib/node.js providing a process object
var binding = process.binding('fs'); fs.exists = function(path, callback) { if (!nullCheck(path, cb)) return; binding.stat(pathModule._makeLong(path), cb); function cb(err, stats) { if (callback) callback(err ? false : true); } };
The binding object does the heavy lifting
NODE_SET_METHOD(target, "stat", Stat); static void Stat(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args.GetIsolate()); HandleScope scope(env->isolate()); if (args.Length() < 1) return TYPE_ERROR("path required"); if (!args[0]->IsString()) return TYPE_ERROR("path must be a string"); // etc.. }
Developed by project odd at Red Hat.
Apache 2.0 License
// Called by Node's os module. // Node has no idea and does not care that a Java method // is used to obtain and return the results. exports.getTotalMem = function() { return java.lang.Runtime.getRuntime().totalMemory(); };
Unlike V8, the JS runtimes on the JVM provide direct access to native objects
Asynchronous I/O & Event Loop
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/');
(function(process) { this.global = this; function startup() { var EventEmitter = NativeModule.require('events').EventEmitter; process.__proto__ = Object.create(EventEmitter.prototype, { constructor: { value: process.constructor } }); EventEmitter.call(process); process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated // etc... });
Node.js main function takes a JS/Java process object
protected static final String NODE_JS = "node.js"; protected static final String PROCESS = "nodyn/process.js"; public NodeProcess initialize() { NodeProcess javaProcess = new NodeProcess(this); getEventLoop().setProcess(javaProcess); DynJS runtime = new DynJS(config); JSObject global = runtime.getGlobalContext().getObject(); ExecutionContext context = runtime.getDefaultExecutionContext(); JSFunction processFunction = (JSFunction) runScript(PROCESS); context.call(processFunction, global, javaProcess); JSFunction nodeFunction = (JSFunction) runScript(NODE_JS); context.call(nodeFunction, global, javaProcess); return javaProcess; }
public Object binding(String name) { Object binding = this.bindings.get(name); if (binding == null) { binding = loadBinding(name); this.bindings.put(name, binding); } return binding; }
@Override public Object loadBinding(String name) { try { this.runner.withSource("__native_require('nodyn/bindings/" + name + "');"); return runner.execute(); } catch(Throwable t) { this.handleThrowable(t); } return null; }
binding.stat = function(path, callback) { path = possiblyRelative(path); function work() { return buildStat(path, function(stat) { return posix.stat(path, stat); }); } return executeWork(work.bind(this), callback, true); };
var binding = process.binding('fs'); fs.exists = function(path, callback) { if (!nullCheck(path, cb)) return; // Now this node.js code is calling our Java/JS functions binding.stat(pathModule._makeLong(path), cb); function cb(err, stats) { if (callback) callback(err ? false : true); } };
Now this node.js code calls Javascript functions backed by Java
Pure Node.js Javascript running on the JVM