Java学习:J2V8与Javet的对比
V8是谷歌开发的开源JavaScript引擎。它被赞誉为快速、应用最新的ES等各种优点。V8是用C++编写的,但如果要从Java使用V8,就需要使用包装器。
- 一番有名なのは、J2V8です。だが更新が止まっているみたいで、windows向けのバージョンは2016年の4.6.0まで、async/awaitはサポートしていないです。詳細は以下のリンクから確認してください。
- 2番めは、javetです。V8の2023年10月のv11.8.172.15、node.jsも9月v20.8.0を利用されています。認知度がJ2V8よりちょっと低いかもしれません。後発ですからJ2V8より使い勝手がいいです。
<dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet</artifactId>
<version>3.0.0</version>
</dependency>
J2V8和Javet在使用上的差异。
测试a.js
global.myVar="aaaaaaaaaa";
testb.js 的中文释义可以是 “测试b.js”。
global.myVar="bbbbbbbbbb";
测试J2V8.java
import java.io.File;
import java.io.IOException;
import com.caoccao.javet.exceptions.JavetException;
import com.eclipsesource.v8.NodeJS;
public class TestJ2V8 {
public static void main(String[] args) throws IOException, InterruptedException, JavetException {
final NodeJS nodeJS = NodeJS.createNodeJS();
File testa=new File("testa.js");
nodeJS.exec(testa);
File testb=new File("testb.js");
nodeJS.exec(testb);
while (nodeJS.isRunning()) {//実行完了まで待つ
nodeJS.handleMessage();
}
System.out.println(nodeJS.getRuntime().getString("myVar"));
nodeJS.release();
}
}
TestJavet.java的测试
import java.io.File;
import java.io.IOException;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.executors.IV8Executor;
public class TestJavet {
public static void main(String[] args) throws IOException, InterruptedException, JavetException {
try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {
IV8Executor iV8Executor=v8Runtime.getExecutor(new File("testa.js"));
iV8Executor.executeVoid();
v8Runtime.await();//実行完了まで待つ
iV8Executor=v8Runtime.getExecutor(new File("testb.js"));
iV8Executor.executeVoid();
v8Runtime.await();//実行完了まで待つ
System.out.println(v8Runtime.getGlobalObject().getString("myVar"));
}
}
}
javet的v8Runtime.await()调用与j2v8中的while (nodeJS.isRunning())具有类似的功能,但v8Runtime.await()可以被调用多次。而while (nodeJS.isRunning())只能被调用一次,执行后V8将处于停止状态,无法再执行更多的js文件。j2v8没有类似于v8Runtime.await()的功能,因为它是在2016年之前的版本。
并且,由于J2V8无法作为EFW的loadWithGlobalPool函数的内置JavaScript引擎使用,因此无法从池中获取并返回引擎的使用。这是因为引擎的使用不仅限于一次,而是会多次间歇性地发生。
另外,Javet具有Primitive Converter和Object Converter的机制,可以自动进行Java和JavaScript之间的转换。J2v8中存在类似的Primitive Converter机制,但没有等效的Object Converter机制。当从Java将Byte[]传递到引擎时,我们需要手动将其转换为V8Array并传递给引擎。这将导致额外的学习和工作量。
J2V8和Javet在多线程方面的区别
根据结论来看,J2V8不允许多线程。Javet允许多线程。
- まずJ2V8とJavetのラインタイムをstatic変数に定義します。
package test;
import com.eclipsesource.v8.V8;
public class TestJ2V82 {
public static V8 runtime = V8.createV8Runtime();
static {
runtime = V8.createV8Runtime();
runtime.executeVoidScript("var c=0;function hello(){c++;return c;};");
}
}
package test;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
public class TestJavet2 {
public static V8Runtime v8Runtime;
static {
try {
v8Runtime = V8Host.getNodeInstance().createV8Runtime();
v8Runtime.getExecutor("var c=0;function hello(){c++;return c;};").executeVoid();
} catch (JavetException e) {
e.printStackTrace();
}
}
}
我将创建一个使用各自的静态变量的JSP文件test_subJ2V8.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="test.TestJ2V82"%>
<%@ page import="com.eclipsesource.v8.V8"%>
<%
V8 runtime =TestJ2V82.runtime;
out.println(runtime.executeStringScript("''+hello();"));
out.println("<br>");
out.println(runtime.executeStringScript("''+hello();"));
%>
测试_subJavet.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="test.TestJavet2"%>
<%@ page import="java.io.File"%>
<%@ page import="java.io.IOException"%>
<%@ page import="com.caoccao.javet.exceptions.JavetException"%>
<%@ page import="com.caoccao.javet.interop.V8Host"%>
<%@ page import="com.caoccao.javet.interop.V8Runtime"%>
<%@ page import="com.caoccao.javet.interop.executors.IV8Executor"%>
<%
V8Runtime v8Runtime=TestJavet2.v8Runtime;
out.println(v8Runtime.getExecutor("hello()").executeInteger());
out.println("<br>");
out.println(v8Runtime.getExecutor("hello()").executeInteger());
%>
我将创建一个测试页面,以同时调用10次上述的JSP页面。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="efw" uri="efw" %>
<!DOCTYPE HTML>
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE"CONTENT="TEXT/HTML;CHARSET=UTF-8">
<TITLE>efw Output Test</TITLE>
<!-- Efwクライアントの取り込み-->
<efw:Client lang="jp"/>
<script>
function testJavetM(flg){
$("#pdf0")[0].src="";
$("#pdf1")[0].src="";
$("#pdf2")[0].src="";
$("#pdf3")[0].src="";
$("#pdf4")[0].src="";
$("#pdf5")[0].src="";
$("#pdf6")[0].src="";
$("#pdf7")[0].src="";
$("#pdf8")[0].src="";
$("#pdf9")[0].src="";
setTimeout(function(){
$("#pdf0")[0].src="test_sub"+flg+".jsp";
$("#pdf1")[0].src="test_sub"+flg+".jsp";
$("#pdf2")[0].src="test_sub"+flg+".jsp";
$("#pdf3")[0].src="test_sub"+flg+".jsp";
$("#pdf4")[0].src="test_sub"+flg+".jsp";
$("#pdf5")[0].src="test_sub"+flg+".jsp";
$("#pdf6")[0].src="test_sub"+flg+".jsp";
$("#pdf7")[0].src="test_sub"+flg+".jsp";
$("#pdf8")[0].src="test_sub"+flg+".jsp";
$("#pdf9")[0].src="test_sub"+flg+".jsp";
},100);
}
</script>
</HEAD>
<BODY>
<button onclick="testJavetM('Javet');">マルチJavet</button>
<button onclick="testJavetM('J2V8');">マルチJ2V8</button>
<br>
<iframe id="pdf0" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf1" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf2" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf3" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf4" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf5" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf6" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf7" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf8" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf9" src="" style="width:400px;height:300px"></iframe>
</BODY>
</HTML>
- マルチスレッドについて、Graaljsもだめです。QuickJSもだめです。逆にむかしのNashornとRhinoは可能です。ようやくES2015以上サポート且つマルチ可能のエンジンを見つかりました。
結果
Javet很好,我们来试试使用吧。