我有一个自定义Nashorn运行时,我设置了一些全局函数和对象 – 其中一些是无状态的,其中一些是有状态的.针对此运行时,我正在运行一些自定义脚本.

对于每次执行,我计划创建一个由全局上下文支持的新上下文:

myContext.setBindings(engine.createBindings(),ScriptContext.ENGINE_ScopE);
engine.eval(myScript,myContext);

根据我读到的内容,对全局范围的任何修改(从脚本的角度来看)将仅限于我创建的新上下文.

这些脚本在评估时会公开一些对象(具有明确定义的名称和方法名称).我可以通过将引擎转换为invocable来调用对象上的方法.但是,我如何知道函数运行的上下文?这甚至是一个问题,还是该功能的执行上下文是根据评估它的上下文设置的?

在多线程情况下,我可以期待什么行为,其中所有线程共享相同的脚本引擎实例,并且它们都尝试运行相同的脚本(公开全局对象).当我然后在对象上调用方法时,函数会在哪个上下文中运行?它将如何知道要使用的对象实例?

我期待看到一个invoke方法,我可以指定上下文,但似乎并非如此.有没有办法做到这一点,还是我完全错了?

我知道解决这个问题的一个简单方法是每次执行创建一个新的脚本引擎实例,但据我所知,我会失去优化(特别是在共享代码上).话虽如此,这里会预先编译帮助吗?

解决方法

我想通了.我遇到的问题是invokeFunction会抛出NoSuchMethodException,因为自定义脚本公开的函数在引擎默认范围的绑定中不存在:
ScriptContext context = new SimpleScriptContext();
context.setBindings(nashorn.createBindings(),ScriptContext.ENGINE_ScopE);
engine.eval(customScriptSource,context);
((invocable) engine).invokeFunction(name,args); //<- NoSuchMethodException thrown

所以我要做的就是按名称从上下文中提取函数并像这样明确地调用它:

JSObject function = (JSObject) context.getAttribute(name,ScriptContext.ENGINE_ScopE);
function.call(null,args); //call to JSObject#isFunction omitted brevity

这将调用新创建的上下文中存在的函数.您还可以通过以下方式调用对象上的方法:

JSObject object = (JSObject) context.getAttribute(name,ScriptContext.ENGINE_ScopE);
JSObject method = (JSObject) object.getMember(name);
method.call(object,args);

call抛出一个未经检查的异常(Throwable包装在RuntimeException或NashornException中,已用JavaScript堆栈信息初始化)所以如果你想提供有用的反馈,你可能必须明确地处理它.

这样线程就不会互相跳过,因为每个线程都有一个单独的上下文.我还能够在线程之间共享自定义运行时代码,并确保自定义运行时公开的可变对象的状态更改被上下文隔离.

为此,我创建了一个CompiledScript实例,其中包含我的自定义运行时库的编译表示:

public class Runtime {

    private ScriptEngine engine;
    private CompiledScript compiledRuntime;

    public Runtime() {
        engine = new NashornScriptEngineFactory().getScriptEngine("-strict");
        String source = new Scanner(
            this.getClass().getClassLoader().getResourceAsstream("runtime/runtime.js")
        ).useDelimiter("\\Z").next();

        try {
            compiledRuntime = ((Compilable) engine).compile(source);
        } catch(ScriptException e) {
            ...
        }
    }

    ...
}

然后当我需要执行脚本时,我会评估编译后的源代码,然后根据该上下文评估脚本:

ScriptContext context = new SimpleScriptContext();
context.setBindings(engine.createBindings(),ScriptContext.ENGINE_ScopE);

//Exception handling omitted for brevity

//Evaluate the compiled runtime in our new context
compiledRuntime.eval(context); 

//Evaluate the source in the same context
engine.eval(source,context);

//Call a function
JSObject jsObject = (JSObject) context.getAttribute(function,ScriptContext.ENGINE_ScopE);
jsObject.call(null,args);

我用多个线程测试了这个,我能够确保状态更改仅限于属于单个线程的上下文.这是因为编译的表示在特定的上下文中执行,这意味着由它公开的任何事件的实例都限定在该上下文中.

这里的一个小缺点是,您可能不必要地重新评估不需要具有线程特定状态的对象的对象定义.要解决这个问题,请直接在引擎上对它们进行评估,这会将这些对象的绑定添加到引擎的ENGINE_ScopE中:

public Runtime() {
    ...
    String shared = new Scanner(
        this.getClass().getClassLoader().getResourceAsstream("runtime/shared.js")
    ).useDelimiter("\\Z").next();

    try {
        ...        
        nashorn.eval(shared);
        ...
    } catch(ScriptException e) {
        ...
    }
}

然后,您可以从引擎的ENGINE_ScopE填充特定于线程的上下文:

context.getBindings(ScriptContext.ENGINE_ScopE).putAll(engine.getBindings(ScriptContext.ENGINE_ScopE));

您需要做的一件事是确保您公开的任何此类对象都已冻结.否则,可以重新定义或添加属性.

javascript – 在Nashorn中的特定上下文中执行函数的更多相关文章

  1. html5利用canvas实现颜色容差抠图功能

    这篇文章主要介绍了html5利用canvas实现颜色容差抠图功能,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. Canvas图片分割效果的实现

    这篇文章主要介绍了Canvas图片分割效果的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5 Canvas实现放大镜效果示例

    这篇文章主要介绍了HTML5 Canvas实现放大镜效果示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  4. Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)

    这篇文章主要介绍了Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. html5如何在Canvas中实现自定义路径动画示例

    本篇文章主要介绍了html5如何在Canvas中实现自定义路径动画示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  6. canvas实现圆形进度条动画的示例代码

    这篇文章主要介绍了canvas实现圆形进度条动画的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. 教你使用Canvas处理图片的方法

    本篇文章主要介绍了教你使用Canvas处理图片的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. 手把手教你实现一个canvas智绘画板的方法

    这篇文章主要介绍了手把手教你实现一个canvas智绘画板的方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. 使用canvas来完成线性渐变和径向渐变的功能的方法示例

    这篇文章主要介绍了使用canvas来完成线性渐变和径向渐变的功能的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  10. H5 canvas实现贪吃蛇小游戏

    本篇文章主要介绍了H5 canvas实现贪吃蛇小游戏,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部