`

JS 与 AS 交互及效率对比

阅读更多

 

    想象下有这样的业务场景,我用flash实现了文件的上传,上传完之后,我们可能需要在页面上弹个提示框告诉用户上传结果。我们不可能把所有东西都放在flash里完成,因为那样flash的文件会加大,而且也不够灵活,因为flash是需要编译后才能跑的,所以我们最好把能用js实现的都剥离出来,让flash只做一些核心的功能。这样,我们就需要用as去调用js。同样的,如果js操作完了想通知到flash,就需要用js去调用flash中的as方法。此时可以看作as是js增强的一部分。

     不管是as调用js,还是js调用as,其实都围绕ExternalInterface。ExternalInterface 类是外部 API,这是一个在 ActionScript 和 Flash Player 容器之间实现直接通信的应用程序编程接口。当然插入flash的html标签中<param name='allowScriptAccess' value ='always' /> 不能为never,如果设置成never一下所有都是空谈了,一般情况下都设置成always,它也可以接受具体的domain或者IP。

     ExternalInterface有两个提供相互调用的静态方法:
     /**
      * @param functionName {String} 
      * @param closure {Function}
      * @usage 将 ActionScript 方法注册为可提供外部js调用。
      */
     addCallback(functionName:String, closure:Function):void 

     /**
      * @param functionName {String} 
      * @param arguments {Function} (optional)
      * @usage 调用页面上的js。
      */
     call(functionName:String, ... arguments):*
 

Example 1:
假如页面上有一个叫sayHi的js函数, 如下:
window.onload=function (){
     function sayHi(){alert('Hello JS')}
}
 
要在flash中调用这个函数,可以用两个办法:
navigateToURL(new URLRequest( 'javascript:sayHi()' ), '_self'); //实际上打开一个新窗口,只不过url是javascript:sayHi(),这是土鳖方法
ExternalInterface.call( 'sayHi');// 用到了ExternalInterface类,这种方法也是adobe推荐的做法
 
运行结果,发现两个都没法执行,这是因为flashplayer只能看到页面上全局的javascript,所以要想能让flash拿到这个js函数,必须暴露出来。修改代码在运行
window.onload=function (){
     function sayHi(){alert('Hello JS')}
     window['sayHi'] = sayHi;
}
 
代码成功运行了,于是,我们可以总结出一点:提供给flash调用的js函数必须是全局的,获取寄宿在全局对象上的。
     有时候我们只用到了flash的功能,而没用到它的UI所以想把flash隐藏,比如做一个即时通讯的东西,只有通讯部分用到了flash, 当尝试把flash设置成display:none的时候,发现js与as根本无法相互调用,所以说如果需要隐藏flash,设置css是行不通的,可以设置它的宽高为1px来解决。

     如果是想在js中调用as方法,需要用ExternalInterface.addCallback注册as方法,让他暴露在flash实例上。比如flash中有这样的方法:
private function sayHi():void{
     Alert.show('Hi As');
}
External.addCallback('jsSayHi', sayHi);
 
这样就可以在js中执行jsSayHi这个代理方法,它会去执行sayHi这个as方法。jsSayHi这个代理方法会寄宿在flash dom元素上,作为dom元素的方法。
window.onload=function (){
     document.getElementById('flashId').sayHi();
}
 
测试一下,还是发现了问题,有时候能正常运行,但有时候会抛出错误:Uncaught TypeError: Object #<HTMLObjectElement> has no method 'jsSayHi',这是因为即使当前页面onload了,但是flash中的代码初始化还没运行完,所以还没有把代理方法注册到flash dom元素上。(查看实例3-jscallas_b.html)

     那么,flash有没有类似domready的时间点呢?查看好多资料没看到,但是可以模拟一个。我们认识当flash能正常调用页面上的js时,flash能正常跟js进行交互。我们在页面上定义一个flashready函数,让flash回调。
function flashready(){
     document.getElementById('flashId').jsSayHi(); 
     alert('flash is ready');    
}
 

ExternalInterface.call( 'flashready' );
 

     这样js对as的调用就能100%的成功了。

     对于静态资源往往会放在cdn上,比如有一台cdn域名是cdn.com,而主域名确是xxx.com,这样就出现了跨域的问题。浏览器的安全策略导致ajax不能正常的跨域请求,flash player的安全策略同样不允许flash跨域请求和调用。当遇到跨域时,flash player会抛出“安全沙箱冲突错误”。其实flash是支持跨域的,只不过要做一些设置。

     如果是跨域脚本执行,flash中有Secure.allowDomain(somedomain1, somedomain2)来允许制定的url请求,somedomain也可以是通配符"*",也就是不做源限制。如果flash的url是https的链接,则需要用allowInsecureDomain()来做沙箱桥,但如果当前html也是https,那不需要用它。尽量避免使用allowInsecureDomain会削弱https的安全性。但是在一些国产浏览器中,比如腾讯TT,遨游,360等浏览器中,经常会遇到第一次进来js能正常调用flash中的as,但是当刷新一次页面,发现调用不成功了。这是因为第二次访问的时候,flash被缓存到了本地,这些浏览器破坏了flash和浏览器的某种约定,所以导致他们不能相互调用。
     这个问题有两个做法:一、当flash文件很小时,用无缓存的方式解决,比如请求后面加随机数。二、延迟Flash的初始化功能。通过将Flash的ExternalInterface.addCallback初始化时间延后一些(比如500ms),就可以解决这个问题。
     顺便提一下,如果是flash中的http/socket等跨域请求,则需要一个叫crossdomain.xml的策略文件。这个文件放在服务器上,如果是跨域请求,在请求真实地址之前会去请求这个安全策略文件。
<cross-domain-policy>
<allow-access-from domain=”*.xxx.com”/>
<allow-access-from domain=”*.xxx.net”/>
<allow-access-from domain=”*.xxxcdn.com”/>
<allow-access-from domain=”*.allyes.org”/>
</cross-domain-policy>
 

     有人可能会考虑js与as之间频繁的相互调用会带来性能问题。简单的做了下测试
测试代码如下:

function flashready(){
       var swf = document.getElementById('performance'), //方案1
       //var swf = {'test':function(){return 1}}, //方案2
			test = swf.test,               
			i = 10000;    
							
	   var start = + new Date;
	   while(i--){
			test.call(swf);
	   }
	   alert(+ new Date - start);                 
}
 
flashready是一个全局的,提供给flash初始完回调的函数。注意代码中把获取flash dom放到一个变量里,因为dom操作本身开销大,如果不这么做会影响精确性。实验结果如下:
测试项目(测10次取平均值) chrome 19 firefox 9 ie6 ie7 ie8 ie9
js调用as 10000次耗时(方案1) 1747ms 1083ms 360ms 557ms 485ms 401ms
js调用js 10000次耗时(方案2) 1ms 4ms 15ms 31ms 15ms 0ms

观察结果,虽然说js与as执行的执行要比js与js之间慢很多很多,但是勉强还是能接受的,即使是最慢的chrome,平均调用一次也只需要0.17ms,但还是要尽量减少相互调用的次数,就像减少http请求一样。

综上所述,js与as的安全交互必须满足:
  1. <param name='allowScriptAccess' value ='always' />   
  2. flash不能隐藏(display:none)  
  3. 等被调用方初始化完成再去调用,as中可以用ExtercalInterface.call('flashready')来告知初始化完成
  4. 跨域执行,必须在flash中设置Secure.allowDomain或者Secure.allowInsecureDomain
最后做下小广告,欢迎加JS&PHP群(166643291)一起进步。

 

分享到:
评论

相关推荐

    js与oc交互demo

    js与oc交互demojs与oc交互demojs与oc交互demojs与oc交互demojs与oc交互demo

    activex与js交互

    activex与js交互,简单易学 内附有activex源码 欢迎大家参考

    WebView与Js交互

    Android 与Js交互的简单实现Demo 你们可以看看,必有收获

    AS3.0与JS交互

    有关FLASH利用AS3.0与网页里javascript产生交互达到信息传递的方法。案例中用了最简单的例子,简单易懂。大家多多交流,共同进步。

    delphi与javascript交互

    本程序列举出 delphi与javascript交互 delphi与html交互 的各种方法

    AS3与JS交互通信(使用swfObject插入Flash)

    4、使用Flash中的ExternalInterface.addCallback方法创建接口,使JS能够调用AS中的函数。 包含swfobject.js与fla源文件。 (*下载swfObject开发版及示例请访问:http://code.google.com/p/swfobject/) 兼容性,...

    swift与JS交互

    swift版使用wkwebview与JS交互

    c#与JavaScript交互

    avascript与c#后台交互 1.在后台c#代码中调用jacascript的方法 javascript代码: &lt;script type="text/javascript" language="javascript"&gt; function test() { alert("oec2003"); return false; } c#代码: ...

    OC 与 js交互

    OC 与 js交互Demo

    JS与OC的交互

    使用JavaScriptCore.framework使得js与oc交互

    svg与js交互

    svg与js交互,主要讲解svg与js的交互,svg与js交互,主要讲解svg与js的交互

    Flex与JS交互

    actionscript与javascript交互

    ChromiumWebBrowser 与js 交互类

    wpf 加载ChromiumWebBrowser 浏览器 与js交互 发消息同信

    OC与js交互

    使用stringByEvaluatingJavaScriptFromString进行oc与js的交互,以及js与oc的交互。用最简单的demo实现最复杂的交互。

    ActiveX组件与JavaScript交互

    ActiveX组件与JavaScript交互ActiveX组件与JavaScript交互ActiveX组件与JavaScript交互

    OC与JS交互

    OC与JS交互demo,谢谢指出不足。OC与JS交互demo,谢谢指出不足。

    as3.0利用ExternalInterface与js交互的播放器

    as3.0利用ExternalInterface与js交互的播放器,重写flvPlayerbeta0.1例子

    js 与 C# 交互

    js 与 C#函数之间的交互调用 js中能调用C#中的函数 C#中也能调用js 中的函数 文档中把调用方法写的很清楚,有实例参考 很好的文档,值得保留

    iOS WKWebView 与js交互详解

    苹果官方推荐的WKWebView与js交互

Global site tag (gtag.js) - Google Analytics