監(jiān)理公司管理系統(tǒng) | 工程企業(yè)管理系統(tǒng) | OA系統(tǒng) | ERP系統(tǒng) | 造價咨詢管理系統(tǒng) | 工程設(shè)計管理系統(tǒng) | 甲方項目管理系統(tǒng) | 簽約案例 | 客戶案例 | 在線試用
X 關(guān)閉

在長時間操作過程中更新顯示

申請免費試用、咨詢電話:400-8352-114

AMTeam.org

在長時間操作過程中更新顯示

作者:Dave Massy

上個月我們討論了使用 DHTML 提供 Web 服務(wù),在接下來的幾個月里,我們將進一步詳細(xì)討論這個主題。在 Web 服務(wù)這個問題上,越是思考它將為 Web 應(yīng)用程序提供的種種可能,我就越感到興奮。我知道這不太好,可這些事情確實讓我興奮。不過,這個月我想我該講講更基本的主題。近幾個月來我卷入了一些關(guān)于這個問題的漫長的電子郵件討論,我想解釋一下這個問題為什么會存在,以及可能的解決方案。這會非常有趣。引起討論的第一封電子郵件一般是這樣寫的:

我編了一個使用 while 循環(huán)的腳本函數(shù),它的執(zhí)行時間很長。盡管我在循環(huán)里加入了一個作為迭代進程的更新顯示的語句,可是總要到例程完成之后才會更新顯示。

郵件中往往附著這樣一段腳本:

<SCRIPT>





function longtime()

{

var i=0;
while (i<=500)
{
d1.innerHTML="Count ="+i;
i++;
// 以下語句代表一個很長的過程
var j=0;
while (j<=10000)
j++;
}
}
</SCRIPT>
<INPUT TYPE="BUTTON" onclick="longtime();" value="Click Me">
<DIV id="d1">This is where the count of iterations should display</DIV>

編寫 DHTML 的新手遇到這種問題并不奇怪。盡管編過一段時間 DHTML 的人會立刻回答:“這還不明顯嗎?”這個問題確實值得好好解釋一番。

這段 HTML 和腳本的預(yù)期效果是在執(zhí)行長時間迭代操作的過程中顯示進度計數(shù)。而實際的效果卻非常糟糕。最明顯的問題是,按下按鈕后會有一個停頓,用戶會看到提示,說腳本將運行很長時間,并詢問是否放棄操作。同時,顯示會更新為計數(shù)值。您可能會注意到出現(xiàn)提示之前的另一個細(xì)微效果:按鈕保持按下狀態(tài),而用戶根本無法使用瀏覽器。正是這一事實(用戶被鎖在瀏覽器之外)導(dǎo)致 Microsoft? Internet Explorer 對用戶發(fā)出提示,以便用戶能夠避免運行時間過長的腳本。

這是為什么?

腳本在 Internet Explorer 中運行的一個原則是:它的運行是不可中斷的。所以,執(zhí)行上面的腳本時,瀏覽器將處于鎖定狀態(tài),直至腳本運行結(jié)束。乍一看來,這象是一個糟糕的設(shè)計,一個缺陷??墒?,如果停下來想一想:如果不這樣做會怎樣,您就可能會意識到,這根本不是缺陷,而是一個邏輯設(shè)計。

讓我們設(shè)想一下,如果上面的腳本按照作者的意圖執(zhí)行,用戶將會在顯示器上看到計數(shù)值從 0 增長到 500。這時,每次顯示更新時就會生成 onresize 和 onchange 這樣的事件。腳本會立即處理這些事件嗎?很可能不,因為這會對腳本運行的原函數(shù)造成影響,例如,全局變量值的變化。另一種方案是,在執(zhí)行原函數(shù)時所有事件均排隊等候處理,但這也會帶來一系列問題,而且與預(yù)期效果所距甚遠。有一點對腳本很有用處,即能夠執(zhí)行并決定內(nèi)容應(yīng)該如何在屏幕上顯示,然后讓所有更新同步發(fā)生,而不是在屏幕的不同部分不斷改變顯示。

那么,為什么會在提示放棄腳本操作時更新顯示呢?這是因為對話框的顯示會導(dǎo)致腳本轉(zhuǎn)讓控制權(quán),所以顯示引擎才有機會更新顯示,顯示當(dāng)前的 DHTML 文檔樹。腳本轉(zhuǎn)讓控制權(quán)的思路非常重要,這一點類似于汽車讓路給其他車輛加入車流。在瀏覽器中,當(dāng)腳本引擎轉(zhuǎn)讓控制權(quán)時,允許顯示引擎取得控制,這時,顯示引擎查看 DHTML 文檔樹,并根據(jù)上次獲得控制后發(fā)生的變化進行更新。這里我已經(jīng)簡化了瀏覽器的內(nèi)部過程。顯示引擎非常智能,能夠找到顯示內(nèi)容中無效并需要調(diào)整的部分。這可能會導(dǎo)致當(dāng)前顯示內(nèi)容的布局變化,繼而強制屏幕的其他部分重新顯示。這里需要注意的重點是,腳本控制權(quán)的轉(zhuǎn)讓允許顯示更新和用戶使用瀏覽器。所以,要使我們的示例腳本達到預(yù)期效果,需要強制腳本轉(zhuǎn)讓控制權(quán)。

使腳本轉(zhuǎn)讓控制權(quán)

要使腳本轉(zhuǎn)讓控制權(quán),開發(fā)人員可以采用下面幾種做法。首先,就像我們已經(jīng)看到的,對話框會強制腳本轉(zhuǎn)讓控制權(quán)。顯然,在我們這個示例里不想使用對話框,因為我們只想更新屏幕,而不想給用戶任何提示。不過,對話框能夠強制腳本轉(zhuǎn)讓控制權(quán)的事實引發(fā)了一個有關(guān)調(diào)試腳本的有趣問題。有時,開發(fā)人員會奇怪為什么一段代碼不象預(yù)期的那樣運行,而一種簡單快捷的方法是在待查代碼中插入如下代碼行,以了解變量 mystuff 的值:

alert("The value of mystuff is: "+mystuff);  

在大多數(shù)情況下,它工作得非常好。不過,因為警告會強制顯示對話框,而腳本將轉(zhuǎn)讓控制權(quán)。這一轉(zhuǎn)讓會導(dǎo)致顯示更新以及某些布局樣式值的變化。所以,后續(xù)腳本流程可能會與腳本中不存在警告時不同。我經(jīng)常使用的一種調(diào)試技巧是在瀏覽器的狀態(tài)欄中顯示變量的值(而不是使用警告):

window.status="The value of mystuff is: "+mystuff;  

這樣腳本的流程不會因為出現(xiàn)對話框而中斷。

另一種強制腳本轉(zhuǎn)讓控制權(quán)的方法是使用超時,在我們的示例腳本中將使用這一技巧。

超時

超時并不僅僅是美式足球中使用的一個奇怪概念。(在美式足球中,超時允許一個隊中斷比賽。)它還是一種強有力的腳本編寫技巧,允許在經(jīng)過一段時間后再調(diào)用腳本??捎玫挠嫊r器方法有兩種:setTimeout(英文)和 setInterval(英文)。它們的功能類似,setTimeout 提供對函數(shù)的唯一一次回調(diào),而 setInterval 按照適當(dāng)?shù)臅r間間隔重復(fù)回調(diào)函數(shù)。這里我們使用 setTimeout。

<SCRIPT>
var i;
function longtime()
{
i=0;
timedIterations();


} function timedIterations()
{
if (i<=500)
{
d1.innerHTML="Count ="+i;
// 下列語句代表需要一段時間的計算
var j=0;
while (j<=10000)
j++;
setTimeout("timedIterations();", 1);
i++;
}


}
</SCRIPT>
<INPUT TYPE="BUTTON" onclick="longtime();" value="Click Me">
<DIV id="d1">This is where the count of iterations should display</DIV>
<SCRIPT>
var i;
function longtime()
{
i=0;
timedIterations();

} function timedIterations()
{
if (i<=1000)
{
d1.innerHTML="Count ="+i;
// 下列語句代表需要一段時間的計算
var j=0;
while (j<=10000)
j++;
setTimeout("timedIterations();", 1);
i++;
}

}
</SCRIPT>
<INPUT TYPE="BUTTON" onclick="longtime();" value="Click Me">
<DIV id="d1">This is where the count of iterations should display</DIV>

在上面的示例中,我們使用了原來的代碼。為清楚起見,我們將其分為兩個函數(shù),其中主函數(shù) timedIterations 使用 setTimeout 來再次調(diào)用其自身。這里 setTimeout 的頻率設(shè)置為 1 毫秒,以便其能夠盡快回調(diào)。不能依賴這些計時器來計算精確的毫秒數(shù),但如果在上述示例中將超時設(shè)置為 1000 毫秒,其結(jié)果將精確到每次迭代耗時一秒。當(dāng)然,您可以根據(jù)所執(zhí)行的任務(wù),自行決定如何將過程劃分為片斷來進行計時迭代。

讓用戶等待

現(xiàn)在這個示例做得很好,不過,我們往往想讓用戶在處理過程中等待,直至處理結(jié)束。一個簡單的實現(xiàn)方法是禁止輸入并顯示等待光標(biāo):

<SCRIPT>
var i;
function longtime()
{
i=0;
b1.style.cursor="wait";
b1.disabled=true;
timedIterations();

} function timedIterations()

{
if (i<=500)
{
d1.innerHTML="Count ="+i;
// 下列語句代表需要一段時間的計算
var j=0;
while (j<=10000)
j++;
setTimeout("timedIterations();", 1);
i++;
}
else
{
b1.style.cursor="";
b1.disabled=false;
}

}
</SCRIPT>
<BODY id=b1>
<INPUT id="ip1" TYPE="BUTTON" onclick="longtime();" value="Click Me">
<DIV id="d1">This is where the count of iterations should display</DIV> </BODY>

在上面的示例中,我加入了一點代碼來禁用整個文檔內(nèi)容,并在進行迭代時顯示等待光標(biāo)。因此,瀏覽器將繼續(xù)更新,用戶不會鎖定它,但同時用戶也不能操作頁面和導(dǎo)致其他事件發(fā)生。當(dāng)然,這種方法非常直接,而您可能希望禁用頁面的某些部分,而用戶仍然能夠通過一種集成的方式來放棄操作?!皠e只是攔住用戶!”

這個月要說的最后一點是:在編寫 DHTML 功能時,重要的一點是不要將用戶與瀏覽器隔離開來。如果整個瀏覽器看起來像是鎖住了,會讓用戶感到非常不快。即使您不希望用戶在執(zhí)行長時間操作時更改頁面上的任何內(nèi)容,也不應(yīng)該這樣??梢栽跒g覽器中使用某種功能給用戶提供當(dāng)前狀態(tài)的反饋,讓用戶感覺良好。最后,我們對示例做了一個非常簡單的修改,顯示一個隨迭代進度而增長的進度欄。

發(fā)布:2007-03-25 13:24    編輯:泛普軟件 · xiaona    [打印此頁]    [關(guān)閉]
相關(guān)文章:
石家莊OA系統(tǒng)
聯(lián)系方式

成都公司:成都市成華區(qū)建設(shè)南路160號1層9號

重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務(wù)大廈18樓

咨詢:400-8352-114

加微信,免費獲取試用系統(tǒng)

QQ在線咨詢