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

在長(zhǎng)時(shí)間操作過(guò)程中更新顯示

申請(qǐng)免費(fèi)試用、咨詢電話:400-8352-114

AMTeam.org

在長(zhǎng)時(shí)間操作過(guò)程中更新顯示

作者:Dave Massy

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

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

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

<SCRIPT>





function longtime()

{

var i=0;
while (i<=500)
{
d1.innerHTML="Count ="+i;
i++;
// 以下語(yǔ)句代表一個(gè)很長(zhǎng)的過(guò)程
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 的新手遇到這種問題并不奇怪。盡管編過(guò)一段時(shí)間 DHTML 的人會(huì)立刻回答:“這還不明顯嗎?”這個(gè)問題確實(shí)值得好好解釋一番。

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

這是為什么?

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

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

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

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

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

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

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

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

這樣腳本的流程不會(huì)因?yàn)槌霈F(xiàn)對(duì)話框而中斷。

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

超時(shí)

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

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


} function timedIterations()
{
if (i<=500)
{
d1.innerHTML="Count ="+i;
// 下列語(yǔ)句代表需要一段時(shí)間的計(jì)算
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;
// 下列語(yǔ)句代表需要一段時(shí)間的計(jì)算
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>

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

讓用戶等待

現(xiàn)在這個(gè)示例做得很好,不過(guò),我們往往想讓用戶在處理過(guò)程中等待,直至處理結(jié)束。一個(gè)簡(jiǎn)單的實(shí)現(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;
// 下列語(yǔ)句代表需要一段時(shí)間的計(jì)算
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>

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

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

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

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

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

咨詢:400-8352-114

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

QQ在線咨詢