博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
把JScript函数模拟为"异步执行"方式
阅读量:5946 次
发布时间:2019-06-19

本文共 2426 字,大约阅读时间需要 8 分钟。

 我们知道"同步"和"异步"这个概念主要是对线程来说的,这里怎么能把JScirpt的函数弄成异步方式来执行呢?! 这样做又有什么意义呢?

    当我们使用JScript来操作DHMTL元素的时候,DHTML元素的可视更新是和脚本的执行作用域有关的,也就是说脚本的执行是必须"间断"的,从而让IE的从message pump里拿到onpaint事件消息,否则DHTML属性变化引起的的可视化更新并不会马上发生。前面说的"间断"不是真正意义上的程序中断,而是脚本执行的一个作用域的变化。
    举个例子来说,如果我们使用下面的JScript语句,我们是不可能模拟出文字变大的动态效果的。

ExpandedBlockStart.gif
<
script
>
InBlock.gif
function  foo(elmt)
ExpandedSubBlockStart.gif
InBlock.gif    
var  fontSize  =   10 ;
InBlock.gif    
for  ( 
var  i = 0  ; i  <   10  ;  ++ i )
ExpandedSubBlockStart.gif     {
InBlock.gif         fontSize  +=   10 ;
InBlock.gif         aDiv.style.fontSize  =  fontSize;
InBlock.gif         dtBegin  =  
new  Date();
ExpandedSubBlockStart.gif         
do {;}
while ((
new  Date()) - dtBegin  <   500 );
ExpandedSubBlockEnd.gif    }  
ExpandedBlockEnd.gif}  
None.gif
</
script
>
None.gif
<
button 
onclick
="foo(this)"
>Click
</
button
>
None.gif
<
div 
id
="aDiv"
>font size
</
div
>

   问题就是脚本执行在这个函数中始终没有离开它的域,IE根本不会在fontSize改变的过程中重绘,而只能在执行10次循环后,显示出fontSize为110的文字(需要注意这里的矛盾并不是那个do while的延时循环,它只是耗点CPU而已)。

   那么这种效果怎么来做呢?必须使用setInterval或者setTimeout来实现,这两个函数将为脚本执行开启新的"线程",不过这些线程也是会block的,而不是真正的多线程的线程,否这就更乱套了,我们也不需要脚本支持广义上的异步执行。下面我这个"异步执行"的函数也就是基于setTimeout的特性来做的。

None.gif
<
html
>
None.gif
<
body
>
None.gif    
<
button 
onclick
="foo(this)"
>
None.gif        Click
</
button
>
None.gif    
<
div 
id
="aDiv"
>
None.gif        font size
</
div
>
None.gif    
<
table
>
None.gif        
<
tbody
>
None.gif            
<
tr
>
None.gif                
<
td
>
None.gif                    
<
button 
onclick
="__doHeavyWork"
>
None.gif                        Heavy Work 1
</
button
>
None.gif                
</
td
>
None.gif                
<
td 
rowspan
="2"
>
None.gif                    
<
span 
id
="info"
></
span
>
None.gif                
</
td
>
None.gif            
</
tr
>
None.gif            
<
tr
>
None.gif                
<
td
>
None.gif                    
<
button 
onclick
="doHeavyWork"
>
None.gif                        Heavy Work 2
</
button
>
None.gif                
</
td
>
None.gif            
</
tr
>
None.gif        
</
tbody
>
None.gif    
</
table
>
ExpandedBlockStart.gif    
<
script 
language
="javascript"
>
InBlock.gif
function  doHeavyWork(elmt)
ExpandedSubBlockStart.gif {
InBlock.gif    __doHeavyWork.args  =  [];
InBlock.gif    __doHeavyWork.args.push(elmt);
InBlock.gif    info.innerText  =  'begin
dot.gif';
InBlock.gif    window.setTimeout(__doHeavyWork,  1 );
ExpandedSubBlockEnd.gif}
InBlock.gif
InBlock.gif
function  __doHeavyWork(elmt)
ExpandedSubBlockStart.gif {
InBlock.gif    
if  (  ! elmt )
ExpandedSubBlockStart.gif     { 
InBlock.gif        elmt  =  __doHeavyWork.args[ 0 ];
ExpandedSubBlockEnd.gif    }
InBlock.gif    
var  dtBegin  =  
new  Date();
InBlock.gif    
do
ExpandedSubBlockStart.gif     {
InBlock.gif        
var  a  =   1 + 1 ;
ExpandedSubBlockEnd.gif    }
InBlock.gif    
while ((
new  Date()) - dtBegin  <   2000  );
InBlock.gif    info.innerText  =  elmt.tagName  +  ': mession complete.'
ExpandedSubBlockEnd.gif}
ExpandedBlockEnd.gif 
</
script
>
None.gif
</
body
>
None.gif
</
html
>
None.gif

   点击"Heavy Work 1"按钮,我们是看不到浏览器里面出现"Begin..."的提示的,而只能在最后看到一个"BUTTOM: mession complete."。而点击"Heavy Work 2"按钮,就能看到"Begin..."提示,当任务完成再显示"... complete."。这里使用setTimeout是很常见的了,不过有个小hack,我们可以把原函数的参数通过Function对象(就是大写的Function)带到__doHeavyWork函数中去。上例中我自己建了一个args数组对象来存放参数,因为setTimeout里面只能写函数名,没有办法带参数的,到了__doHeavyWork里,再把args里的参数取出,这样的好处是让代码变得内聚性很强,而不需要全局变量来cache doHeavyWork和__doHeavyWork之间的参数。

   正是由于这里的__doHeavyWork是通过setTimeout后的Timer来启动执行的,已经和doHeavyWork不在同一个域中了,所以我们的info.innerText = 'begin...';在doHeavyWork完成后就会立即显示执行效果,而不会因为函数的流程而block。同时当__doHeavyWork执行后,他又会在自己的域中block起来,所以我说这个"异步执行"方式是引号扩起来的,而不是真正的多线程的异步。

   合理的使用这种JScript函数模拟"异步执行"的方式,可以让复杂的网页,特别是无刷性的网页表现出更好的可视效果。

本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。

你可能感兴趣的文章
接口由40秒到200ms优化记录
查看>>
java 视频播放 多人及时弹幕技术 代码生成器 websocket springmvc mybatis SSM
查看>>
Activiti6.0,spring5,SSM,工作流引擎,OA
查看>>
使用Tooltip会出现一个问题,如果行上出现复选框
查看>>
禁止浏览器缓存js
查看>>
【Redis】安装PHP的redis驱动(二)
查看>>
什么是序列化,为什么要序列化
查看>>
Java保留小数点后有效数字
查看>>
C++中一些类和数据结构的大小的总结
查看>>
mysql开启binlog
查看>>
ctrl + z fg bg
查看>>
工作流引擎Oozie(一):workflow
查看>>
struct框架
查看>>
Deep Learning(深度学习)相关网站
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
oracle进行字符串拆分并组成数组
查看>>
100多个基础常用JS函数和语法集合大全
查看>>
Java8 lambda表达式10个示例
查看>>