摘要:未来的主要发布基于。在中调用函数支持从代码中直接调用定义在脚本文件中的函数。内置了方法,提调用函数并返回结果。当向方法传递新的时,我们会在控制台看到预期的结果实战通过使用实现服务端渲染。工具类实例化工具类,通过该类操作对象。
Nashorn JavaScript引擎是Java SE 8 的一部分,并且和其它独立的引擎例如 Google V8(用于Google Chrome和Node.js的引擎)互相竞争。Nashorn通过在JVM上,以原生方式运行动态的JavaScript代码来扩展Java的功能。
使用NashornJava代码中简单的HelloWorld如下所示:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval("print("Hello World!");");
为了在Java中执行JavaScript,你首先要通过javax.script包创建脚本引擎。
JavaScript代码既可以通过传递JavaScript代码字符串,也可以传递指向你的JS脚本文件的FileReader来执行:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval(new FileReader("script.js"));
Nashorn JavaScript基于 ECMAScript 5.1,但是它的后续版本会对ES6提供支持:
Nashorn的当前策略遵循ECMAScript规范。当我们在JDK8中发布它时,它将基于ECMAScript 5.1。Nashorn未来的主要发布基于ECMAScript 6。在Java中调用JavaScript函数
Nashorn 支持从Java代码中直接调用定义在脚本文件中的JavaScript函数。你可以将Java对象传递为函数参数,并且从函数返回数据来调用Java方法。
var fun1 = function(name) { print("Hi there from Javascript, " + name); return "greetings from javascript"; }; var fun2 = function (object) { print("JS Class Definition: " + Object.prototype.toString.call(object)); };
ScriptEngine内置了invokeFunction方法,提调用javascript函数并返回结果。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval(new FileReader("script.js")); Object result = invocable.invokeFunction("fun1", "Peter Parker"); System.out.println(result); System.out.println(result.getClass()); // Hi there from Javascript, Peter Parker // greetings from javascript // class java.lang.String在JavaScript中调用Java方法
在JavaScript中调用Java方法十分容易。我们首先需要定义一个Java静态方法。
static String fun1(String name) { System.out.format("Hi there from Java, %s", name); return "greetings from java"; }
Java类可以通过Java.typeAPI扩展在JavaScript中引用。它就和Java代码中的import类似。只要定义了Java类型,我们就可以自然地调用静态方法fun1(),然后像sout打印信息。由于方法是静态的,我们不需要首先创建实例。
var MyJavaClass = Java.type("my.package.MyJavaClass"); var result = MyJavaClass.fun1("John Doe"); print(result); // Hi there from Java, John Doe // greetings from java
在使用JavaScript原生类型调用Java方法时,Nashorn 如何处理类型转换?让我们通过简单的例子来弄清楚。
下面的Java方法简单打印了方法参数的实际类型:
static void fun2(Object object) { System.out.println(object.getClass()); }
为了理解背后如何处理类型转换,我们使用不同的JavaScript类型来调用这个方法:
MyJavaClass.fun2(123); // class java.lang.Integer MyJavaClass.fun2(49.99); // class java.lang.Double MyJavaClass.fun2(true); // class java.lang.Boolean MyJavaClass.fun2("hi there") // class java.lang.String MyJavaClass.fun2(new Number(23)); // class jdk.nashorn.internal.objects.NativeNumber MyJavaClass.fun2(new Date()); // class jdk.nashorn.internal.objects.NativeDate MyJavaClass.fun2(new RegExp()); // class jdk.nashorn.internal.objects.NativeRegExp MyJavaClass.fun2({foo: "bar"}); // class jdk.nashorn.internal.scripts.JO4
JavaScript原始类型转换为合适的Java包装类,而JavaScript原生对象会使用内部的适配器类来表示。要记住jdk.nashorn.internal中的类可能会有所变化,所以不应该在客户端面向这些类来编程。
ScriptObjectMirror在向Java传递原生JavaScript对象时,你可以使用ScriptObjectMirror类,它实际上是底层JavaScript对象的Java表示。ScriptObjectMirror实现了Map接口,位于jdk.nashorn.api中。这个包中的类可以用于客户端代码。
下面的例子将参数类型从Object改为ScriptObjectMirror,所以我们可以从传入的JavaScript对象中获得一些信息。
static void fun3(ScriptObjectMirror mirror) { System.out.println(mirror.getClassName() + ": " + Arrays.toString(mirror.getOwnKeys(true))); }
当向这个方法传递对象(哈希表)时,在Java端可以访问其属性:
MyJavaClass.fun3({ foo: "bar", bar: "foo" }); // Object: [foo, bar]
我们也可以在Java中调用JavaScript的成员函数。让我们首先定义JavaScript Person类型,带有属性firstName 和 lastName,以及方法getFullName。
function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.getFullName = function() { return this.firstName + " " + this.lastName; } }
JavaScript方法getFullName可以通过callMember()在ScriptObjectMirror上调用。
static void fun4(ScriptObjectMirror person) { System.out.println("Full Name is: " + person.callMember("getFullName")); }
当向Java方法传递新的Person时,我们会在控制台看到预期的结果:
var person1 = new Person("Peter", "Parker"); MyJavaClass.fun4(person1); // Full Name is: Peter Parker实战
通过使用promise实现服务端渲染。
polyfill由于当前Nashorn基于es5,不支持部分es6对象,我们需要引入polyfill文件,nashorn-polyfill。
该polyfill通过java与JavaScript的结合使用,使Nashorn支持console, process, Blob, Promise等对象和setTimeout, clearTimeout, setInterval, clearInterval等函数。
实例化工具类,通过该类操作Javascript对象。
public class NashornHelper { /** * 用于本类的日志 */ private static final Logger logger = LoggerFactory.getLogger(NashornHelper.class); private static final String JAVASCRIPT_DIR = "static"; // js文件目录 private static final String LIB_DIR = JAVASCRIPT_DIR + File.separator + "lib"; private static final String[] VENDOR_FILE_NAME = {"vendor.js"}; // webpack打包的三方库,如react,lodash private static final String SRC_DIR = JAVASCRIPT_DIR + File.separator + "src"; // 文件目录 private static final String POLYFILL_FILE_NAME = "nashorn-polyfill.js"; private final NashornScriptEngine engine; private static NashornHelper nashornHelper; private static ScriptContext sc = new SimpleScriptContext(); private static ScheduledExecutorService globalScheduledThreadPool = Executors.newScheduledThreadPool(20); // 单例模式 public static synchronized NashornHelper getInstance() { if (nashornHelper == null) { long start = System.currentTimeMillis(); nashornHelper = new NashornHelper(); long end = System.currentTimeMillis(); logger.error("init nashornHelper cost time {}ms", (end - start)); } return nashornHelper; } private NashornHelper(){ long start = System.currentTimeMillis(); engine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn"); Bindings bindings = new SimpleBindings(); bindings.put("logger", logger); // 向nashorn引擎注入logger对象 sc.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); sc.getBindings(ScriptContext.ENGINE_SCOPE).putAll(bindings); sc.setAttribute("__IS_SSR__", true, ScriptContext.ENGINE_SCOPE); sc.setAttribute("__NASHORN_POLYFILL_TIMER__", globalScheduledThreadPool, ScriptContext.ENGINE_SCOPE); engine.setBindings(sc.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.ENGINE_SCOPE); long end = System.currentTimeMillis(); logger.info("init nashornHelper cost time {}ms", (end - start)); try { // 执行js文件 engine.eval(read(LIB_DIR + File.separator + POLYFILL_FILE_NAME)); for (String fileName : NashornHelper.VENDOR_FILE_NAME) { engine.eval(read(SRC_DIR + File.separator + fileName)); } engine.eval(read(SRC_DIR + File.separator + "app.js")); } catch (ScriptException e) { logger.error("load javascript failed.", e); } } // 获取Nashorn作用域下的对象 public ScriptObjectMirror getGlobalGlobalMirrorObject(String objectName) { return (ScriptObjectMirror) engine.getBindings(ScriptContext.ENGINE_SCOPE).get(objectName); } // 调用全局方法 public Object callRender(String methodName, Object... input) { try { return engine.invokeFunction(methodName, input); } catch (ScriptException e) { logger.error("run javascript failed.", e); return null; } catch (NoSuchMethodException e) { logger.error("no such method.", e); return null; } } // 读取文件 private Reader read(String path) { InputStream in = getClass().getClassLoader().getResourceAsStream(path); return new InputStreamReader(in); }
实例化工具类
NashornHelper engine = NashornHelper.getInstance();
执行调用javasript,java中获取promise对象
ScriptObjectMirror promise = (ScriptObjectMirror) engine.callRender("ssr_render");
执行promise的then方法,等待执行完成并回调
promise.callMember("then", fnResolve); ScriptObjectMirror nashornEventLoop = engine.getGlobalGlobalMirrorObject("nashornEventLoop"); nashornEventLoop.callMember("process"); // 执行nashornEventLoops.process()使主线程执行回调函数 int i = 0; int jsWaitTimeout = 1000 * 60; int interval = 200; // 等待时间间隔 int totalWaitTime = 0; // 实际等待时间 while (!promiseResolved && totalWaitTime < jsWaitTimeout) { nashornEventLoop.callMember("process"); try { Thread.sleep(interval); } catch (InterruptedException e) { } totalWaitTime = totalWaitTime + interval; if (interval < 500) interval = interval * 2; i = i + 1; }
回调函数
private Consumer
最后结果已字符串形式存在html中,可将其渲染到页面中.
最后适用场景非浏览器渲染页面,如java离线渲染前端页面到Pdf。
实战 github地址, 前端js项目地址
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/68298.html
摘要:未来的主要发布基于。在中调用函数支持从代码中直接调用定义在脚本文件中的函数。内置了方法,提调用函数并返回结果。当向方法传递新的时,我们会在控制台看到预期的结果实战通过使用实现服务端渲染。工具类实例化工具类,通过该类操作对象。 Nashorn JavaScript引擎是Java SE 8 的一部分,并且和其它独立的引擎例如 Google V8(用于Google Chrome和Node.j...
摘要:未来的主要发布基于。在中调用函数支持从代码中直接调用定义在脚本文件中的函数。下面的函数稍后会在端调用为了调用函数,你首先需要将脚本引擎转换为。调用函数将结果输出到,所以我们会首先看到输出。幸运的是,有一套补救措施。 原文:Java 8 Nashorn Tutorial 译者:飞龙 协议:CC BY-NC-SA 4.0 这个教程中,你会通过简单易懂的代码示例,来了解Nashorn Ja...
摘要:原文译者飞龙协议这个例子展示了如何在的引擎中使用模型。在年三月首次作为的一部分发布,并通过以原生方式在上运行脚本扩展了的功能。将二者放在一起下一个目标是在中,例如在服务器上复用模型。最后,我们在中调用函数。总结在中复用现存的库十分简单。 原文:Using Backbone.js with Nashorn 译者:飞龙 协议:CC BY-NC-SA 4.0 这个例子展示了如何在Java8...
摘要:原文译者飞龙协议这个例子展示了如何在的引擎中使用模型。在年三月首次作为的一部分发布,并通过以原生方式在上运行脚本扩展了的功能。将二者放在一起下一个目标是在中,例如在服务器上复用模型。最后,我们在中调用函数。总结在中复用现存的库十分简单。 原文:Using Backbone.js with Nashorn 译者:飞龙 协议:CC BY-NC-SA 4.0 这个例子展示了如何在Java8...
摘要:如果你想查看运行时模块的加载过程输出结果表示为模块,由于我限制了不再往下输出了,而我们模块又没有别的额外依赖,所以仅有这行输出。 jdk9模块快速入门 列出自带模块:java --list-modulesmac多版本jdk共存:http://adolphor.com/blog/2016...模块规则示意图:showImg(https://segmentfault.com/img/bVb...
阅读 3216·2023-04-25 18:43
阅读 894·2021-11-24 09:39
阅读 1361·2021-10-14 09:43
阅读 3892·2021-09-22 15:58
阅读 1902·2019-08-29 17:18
阅读 411·2019-08-29 14:14
阅读 3080·2019-08-29 13:01
阅读 1619·2019-08-29 12:33