把JScript函數類比為”非同步執行”方式

來源:互聯網
上載者:User

    我們知道"同步"和"非同步"這個概念主要是對線程來說的,這裡怎麼能把JScirpt的函數弄成非同步方式來執行呢?! 這樣做又有什麼意義呢?

    當我們使用JScript來操作DHMTL元素的時候,DHTML元素的可視更新是和指令碼的執行範圍有關的,也就是說指令碼的執行是必須"間斷"的,從而讓IE的從message pump裡拿到onpaint事件訊息,否則DHTML 屬性變化引起的的可視化更新並不會馬上發生。前面說的"間斷"不是真正意義上的程式中斷,而是指令碼執行的一個範圍的變化。

    舉個例子來說,如果我們使用下面的JScript語句,我們是不可能類比出文字變大的動態效果的。

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

   問題就是指令碼執行在這個函數中始終沒有離開它的域,IE根本不會在fontSize改變的過程中重繪,而只能在執行10次迴圈後,顯示出fontSize為110的文字(需要注意這裡的矛盾並不是那個do while的延時迴圈,它只是耗點CPU而已)。

   那麼這種效果怎麼來做呢?必須使用setInterval或者setTimeout來實現,這兩個函數將為指令碼執行開啟新的"線程",不過這些線程也是會block的,而不是真正的多線程的線程,否這就更亂套了,我們也不需要指令碼支援廣義上的非同步執行。下面我這個"非同步執行"的函數也就是基於setTimeout的特性來做的。

<html>
<body>
    <button onclick="foo(this)">
        Click</button>
    <div id="aDiv">
        font size</div>
    <table>
        <tbody>
            <tr>
                <td>
                    <button onclick="__doHeavyWork">
                        Heavy Work 1</button>
                </td>
                <td rowspan="2">
                    <span id="info"></span>
                </td>
            </tr>
            <tr>
                <td>
                    <button onclick="doHeavyWork">
                        Heavy Work 2</button>
                </td>
            </tr>
        </tbody>
    </table>
    <script language="javascript">
function doHeavyWork(elmt)
{
    __doHeavyWork.args = [];
    __doHeavyWork.args.push(elmt);
    info.innerText = 'begin';
    window.setTimeout(__doHeavyWork, 1);
}

function __doHeavyWork(elmt)
{
    if ( !elmt )
    { 
        elmt = __doHeavyWork.args[0];
    }
    var dtBegin = new Date();
    do
    {
        var a = 1+1;
    }
    while((new Date())-dtBegin < 2000 );
    info.innerText = elmt.tagName + ': mession complete.'
}
 </script>
</body>
</html>

   點擊"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函數類比"非同步執行"的方式,可以讓複雜的網頁,特別是無刷性的網頁表現出更好的可視效果。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.