且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

把JScript函数模拟为"异步执行"方式

更新时间:2022-08-22 08:19:41

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


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

    举个例子来说,如果我们使用下面的JScript语句,我们是不可能模拟出文字变大的动态效果的。

把JScript函数模拟为"异步执行"方式<script>
把JScript函数模拟为"异步执行"方式
function foo(elmt)
把JScript函数模拟为"异步执行"方式

把JScript函数模拟为"异步执行"方式    
var fontSize = 10;
把JScript函数模拟为"异步执行"方式    
for ( var i=0 ; i < 10 ; ++i )
把JScript函数模拟为"异步执行"方式    
{
把JScript函数模拟为"异步执行"方式         fontSize 
+= 10;
把JScript函数模拟为"异步执行"方式         aDiv.style.fontSize 
= fontSize;
把JScript函数模拟为"异步执行"方式         dtBegin 
= new Date();
把JScript函数模拟为"异步执行"方式         
do{;}while((new Date())-dtBegin < 500);
把JScript函数模拟为"异步执行"方式    }
 
把JScript函数模拟为"异步执行"方式}
 
把JScript函数模拟为"异步执行"方式
</script>
把JScript函数模拟为"异步执行"方式<button onclick="foo(this)">Click</button>
把JScript函数模拟为"异步执行"方式<div id="aDiv">font size</div>

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

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

把JScript函数模拟为"异步执行"方式<html>
把JScript函数模拟为"异步执行"方式<body>
把JScript函数模拟为"异步执行"方式    <button onclick="foo(this)">
把JScript函数模拟为"异步执行"方式        Click</button>
把JScript函数模拟为"异步执行"方式    <div id="aDiv">
把JScript函数模拟为"异步执行"方式        font size</div>
把JScript函数模拟为"异步执行"方式    <table>
把JScript函数模拟为"异步执行"方式        <tbody>
把JScript函数模拟为"异步执行"方式            <tr>
把JScript函数模拟为"异步执行"方式                <td>
把JScript函数模拟为"异步执行"方式                    <button onclick="__doHeavyWork">
把JScript函数模拟为"异步执行"方式                        Heavy Work 1</button>
把JScript函数模拟为"异步执行"方式                </td>
把JScript函数模拟为"异步执行"方式                <td rowspan="2">
把JScript函数模拟为"异步执行"方式                    <span id="info"></span>
把JScript函数模拟为"异步执行"方式                </td>
把JScript函数模拟为"异步执行"方式            </tr>
把JScript函数模拟为"异步执行"方式            <tr>
把JScript函数模拟为"异步执行"方式                <td>
把JScript函数模拟为"异步执行"方式                    <button onclick="doHeavyWork">
把JScript函数模拟为"异步执行"方式                        Heavy Work 2</button>
把JScript函数模拟为"异步执行"方式                </td>
把JScript函数模拟为"异步执行"方式            </tr>
把JScript函数模拟为"异步执行"方式        </tbody>
把JScript函数模拟为"异步执行"方式    </table>
把JScript函数模拟为"异步执行"方式    <script language="javascript">
把JScript函数模拟为"异步执行"方式
function doHeavyWork(elmt)
把JScript函数模拟为"异步执行"方式
{
把JScript函数模拟为"异步执行"方式    __doHeavyWork.args 
= [];
把JScript函数模拟为"异步执行"方式    __doHeavyWork.args.push(elmt);
把JScript函数模拟为"异步执行"方式    info.innerText 
= 'begin把JScript函数模拟为"异步执行"方式';
把JScript函数模拟为"异步执行"方式    window.setTimeout(__doHeavyWork, 
1);
把JScript函数模拟为"异步执行"方式}

把JScript函数模拟为"异步执行"方式
把JScript函数模拟为"异步执行"方式
function __doHeavyWork(elmt)
把JScript函数模拟为"异步执行"方式
{
把JScript函数模拟为"异步执行"方式    
if ( !elmt )
把JScript函数模拟为"异步执行"方式    

把JScript函数模拟为"异步执行"方式        elmt 
= __doHeavyWork.args[0];
把JScript函数模拟为"异步执行"方式    }

把JScript函数模拟为"异步执行"方式    
var dtBegin = new Date();
把JScript函数模拟为"异步执行"方式    
do
把JScript函数模拟为"异步执行"方式    
{
把JScript函数模拟为"异步执行"方式        
var a = 1+1;
把JScript函数模拟为"异步执行"方式    }

把JScript函数模拟为"异步执行"方式    
while((new Date())-dtBegin < 2000 );
把JScript函数模拟为"异步执行"方式    info.innerText 
= elmt.tagName + ': mession complete.'
把JScript函数模拟为"异步执行"方式}

把JScript函数模拟为"异步执行"方式 
</script>
把JScript函数模拟为"异步执行"方式</body>
把JScript函数模拟为"异步执行"方式</html>把JScript函数模拟为"异步执行"方式

   点击"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/,如需转载请自行联系原博主。