JS学习十四天----服务器端执行JS代码

服务器端执行JS代码

话说,当今不在客户端使用JS代码才是稀罕事.由于web应用的体验越来越丰富,客户端用JS实现的逻辑也越来越多,这造成的结果就是某些几乎一致的逻辑需要在客户端和服务端各实现一遍,大牛们当然不甘心啊!幸运的是,我们可以在服务器端执行JS代码,谁让JS抱了一根大腿呢...

例如,如今在客户端使用JS进行验证已经是个标准,他可以有效避免用户在正常情况下提交错误的数据,增强用户体验.当然,服务器端的验证也是必不可少的,因为这才是安全性的体现.有些解决方案,,会在服务器端提供优先的验证种类,然后在客户端生成JS代码,并辅助以服务器端的验证框架.这种做法可以追溯到ASP.NET上的一个控件,但这显然会有扩展性,灵活性上的限制,因此都比较倾向与服务器端执行JS代码.

例如,要检查用户名是否合法,我们可能这样写代码:

var checkName=function (name){return /^\w{3,10}$/.test(name);

}

这在客户端验证自然没有任何问题,服务器端就要借助一些JavaScript执行引擎了。在.NET平台上有例如比较新的IronJS项目,这是个基于DLR的JavaScript执行引擎,十分重视性能,从作者博客上的评测结果来看,甚至领先于以速度见长的V8。可惜的是,IronJS还没有完整实现ECMAScript 3.0,还缺少一些重要功能,例如正则表达式。

Jint是一个.NET平台上较早的JavaScript执行引擎,因此与DLR关系不大,因此可能不太容易与IronPython,IronRuby等语言进行互操作。用它来执行一些简单的JavaScript脚本不成问题,例如上面的代码:

var jint = new Jint.JintEngine();jint.Run(@"var checkName = function(name) { return /^\w{3,10}$/.test(name); }");Console.WriteLine(jint.CallFunction("checkName", "jeffz")); // TrueConsole.WriteLine(jint.CallFunction("checkName", "hello world")); // False

只可惜,在实际使用中,Jint不支持多线程的环境,即我们无法在多个线程下同时调用jint的CallFunction方法,但是如果每次都重新Run一遍JavaScript代码,也会带来较多的性能开销。其实要解决这个问题也并不困难,构造一个对象池即可,.NET 4中提供了并行容器(如ConcurrentStack,ConcurrentQueue),实现一个简单的对象池可谓不费吹灰之力。

这方面Jurassic的表现要好的多,这是一个构建于.NET 4.0的JavaScript执行引擎:

var engine = new Jurassic.ScriptEngine();engine.Evaluate(@"var checkName = function(name) { return /^\w{3,10}$/.test(name); }");Console.WriteLine(engine.CallGlobalFunction<bool>("checkName", "jeffz"));Console.WriteLine(engine.CallGlobalFunction<bool>("checkName", "hello world"));

此外,从Benchmark上来看,Jurassic性能也比Jint有所提高,但还是远远落后于V8,甚至IE 8里的JavaScript引擎。而且,它还提供了一个基于Silverlight控制台,您可以在浏览器里把玩一番。

令人感到意外的是,Jint和Jurassic作为JavaScript执行引擎都有一些严重的问题,那便是不能正确运行showdown.js(JavaScript实现的Markdown转化器)——虽然我并没有发现showdown.js中有过于复杂的内容,基本就是些字符串操作吧。原本我还想把它们用在mono中,既然如此也就不做进一步尝试了。不过,经过简单的实验,Jurassic似乎使用了mono 2.8中尚不支持的接口,但也有可能只是Jurassic控制台中的问题。

有趣的是,.NET平台下最靠谱的JavaScript执行引擎居然是Rhino JavaScript,最近一次发布是在2009年3月,不过实现的十分完整。要说缺点,可能就是使用起来比较麻烦,还有,这是个Java项目。

嗯,我没有开玩笑,我们完全可以在.NET平台下使用Rhino JavaScript:

var cx = Context.enter();try{    var scope = cx.initStandardObjects();    cx.evaluateString(scope, @"var checkName = function(name) { return /^\w{3,10}$/.test(name); }", "checkName.js", 1, null);    var func = (Function)scope.get("checkName", scope);     Console.WriteLine(Context.toString(func.call(cx, scope, scope, "jeffz")));    Console.WriteLine(Context.toString(func.call(cx, scope, scope, "hello world"));}finally {    Context.exit();}

因为我们有IKVM.NET。mono等.NET开源社区上有大量宝藏,就看您能利用多少了。我用ikvmc把js.jar转化为RhinoJs.dll之后就可以直接使用,效果很好,对调试也有很好的支持(如果JavaScript执行时出现了错误,则VS会直接带您至出错的那行)。性能也是比较令人满意的,在我的Mac OSX上安装的Ubuntu Server 10.10虚拟机,单线程转化并过滤博客上最近的3800条评论,大约耗时20秒。试验时Host上还开着一个Windows 7虚拟机,还有大量浏览器等应用程序,并不十分空闲。

您可能知道,我的博客目前是基于mono 2.6的,其中比较有特色的地方便是评论功能了,我使用Markdown标记,并提供了实时的预览功能,这自然需要在客户端解释Markdown标记,并进行过滤。目前,我还在服务器使用了C#实现的Markdown转化器及过滤逻辑,但在某些特殊情况下结果会有所不同,且需要维护两套代码。不久以后,我会将把博客升级为ASP.NET 4.0及mono 2.8(C# 4.0的dynamic特性在某些情况下的确比较方便),并且在服务器端使用IKVM.NET + Rhino JavaScript执行相同转化代码。从效果上来看还是十分令人满意的。

值得一提的是,其实在.NET平台上还有一个基于DLR的JavaScript执行引擎,是为RemObjects Script for .NET,据称也支持mono。只可惜它并不是开源产品(不过公开了源代码),且授权协议要求我们最多在5台机器上安装代码,且只供我们自己使用,于是我就没有对它有关注太多了。

JS的第一部分完事了,本来第二部分还是想按照书上的指示下下去,发现没啥意思.

我想这是写点关于设计模式的东西,还是那句话,敲代码不是计算机技术,要掌握一点原理性的东西还有思想上的东西.

大三一年不准备学代码了,学原理,学思想!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-02 10:20:27

JS学习十四天----服务器端执行JS代码的相关文章

JS学习十四天----server端运行JS代码

server端运行JS代码 话说,当今不在client使用JS代码才是稀罕事.因为web应用的体验越来越丰富,client用JS实现的逻辑也越来越多,这造成的结果就是某些差点儿一致的逻辑须要在client和服务端各实现一遍,大牛们当然不甘心啊!幸运的是,我们能够在server端运行JS代码,谁让JS抱了一根大腿呢... 比如,现在在client使用JS进行验证已经是个标准,他能够有效避免用户在正常情况下提交错误的数据,增强用户体验.当然,server端的验证也是不可缺少的,由于这才是安全性的体现

Ext JS学习第四天 我们所熟悉的javascript(三)

此文用来记录学习笔记: •javascript之函数 •this关键字的使用 –this关键字总是指向调用者,谁调用函数,this就指向谁 •call.apply的使用 –call和apply主要应用与框架底层,用于绑定函数的执行环境/作用域 •块的概念 –和高级程序语言不同,js里没有块的概念,我们一般用小括号包裹块级作用域 •闭包:掌握闭包必须要深入清楚的概念 –执行环境 –作用域链 –垃圾回收机制 附上栗子 代码 1 // This 关键字 在javascript里的使用 2 //this

Oracle学习(十四):管理用户安全

--用户(user) SQL> --创建名叫 grace 密码是password 的用户,新用户没有任何权限 SQL> create user grace identified by password; 验证用户: 密码验证方式(用户名/密码) 外部验证方式(主机认证,即通过登陆的用户名) 全局验证方式(其他方式:生物认证方式.token方式) 优先级顺序:外部验证>密码验证 --权限(privilege) 用户权限有两种: System:允许用户执行对于数据库的特定行为,例如:创建表.

three.js 源码注释(三十四)Texture/Texture.js

商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化.GOLANG.Html5.WEBGL.THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 俺也是刚开始学,好多地儿肯定不对还请见谅. 以下代码是THREE.JS 源码文件中Texture/Texture.js文件的注释. 更多更新在 : https://gi

前端学习(33)~js学习(十):函数

关于函数的核心内容: 函数有哪几种定义和调用方式 this:函数内部的 this 指向.如何改变 this 的指向. 函数的严格模式 高阶函数:函数作为参数传递.函数作为返回值传递 闭包:闭包的作用 递归:递归的两个条件 深拷贝和浅拷贝的区别 函数的介绍 函数:就是将一些功能或语句进行封装,在需要的时候,通过调用的形式,执行这些语句. 函数也是一个对象 使用typeof检查一个函数对象时,会返回function 函数的作用: 将大量重复的语句抽取出来,写在函数里,以后需要这些语句的时候,可以直接

JS学习第四天----可选的分号

可选的分号 和某些语言一样,JS使用分号(;)将语句分隔开.这对增强代码的可读性和整洁性是很重要的:缺少分隔符,一条语句的结束就成了下一条语句,你好像在和别人讲对讲机的时候,没说完一句话,都要说over一样,表示你说完了.在JS中,如果语句各自独占一行,通畅可以省略语句之间的分号.许多JS程序员使用分号来明确标记语句的结束,及时在丙烷完全需要分号的时候也是如此.另一种风格是,在任何可以省略分好的地方都将其省略,只有在不得不用的时候才使用分号.不管采用哪种变成风格,关于JS中可选分号的问题有几点需

three.js 源码注释(六十四)objects/Skeleton.js

商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化.GOLANG.Html5.WEBGL.THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 俺也是刚开始学,好多地儿肯定不对还请见谅. 以下代码是THREE.JS 源码文件中objects/Skeleton.js文件的注释. 更多更新在 : https://g

three.js 源码注释(五十四)Material /SpriteMaterial.js

商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化.GOLANG.Html5.WEBGL.THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 俺也是刚开始学,好多地儿肯定不对还请见谅. 以下代码是THREE.JS 源码文件中materials/SpriteMaterial.js文件的注释. 更多更新在 : h

three.js 源码注释(十四)Math/Sphere.js

商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化.GOLANG.Html5.WEBGL.THREE.JS,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 俺也是刚开始学,好多地儿肯定不对还请见谅. 以下代码是THREE.JS 源码文件中Math/Sphere.js文件的注释. 更多更新在 : https://github