2010-06-28 36 views
14

假設我想阻止Javascript執行某些奇怪的原因,我該怎麼做。 JS中沒有sleep()。請不要說做一段時間()循環,因爲這是不好的。我可以做一個window.showModalDialog,並將window.close放在模態對話框中,使用setTimeout很短的時間,以便用戶不會注意到對話框。這將會像睡眠時間很短,如果需要,我可以多次打電話。有沒有其他的方法?Javascript中的sleep()

爲了詳細說明,我的使用案例是HTML5 SQL數據庫提供了異步API,但是我想將它用於存儲永遠不會很大的samll webapp。因此,不需要異步API,因爲小商店的查詢將在客戶端運行。所以我想用同步api編寫一個ORM,以便開發人員可以更輕鬆地使用它。爲了彌合這種異步同步api,我需要睡眠。

+1

你能說一點你的例子嗎?這聽起來像是一個'setInterval()',但是我並沒有100%清楚你的用例。 – 2010-06-28 23:12:09

回答

13

window.setTimeoutwindow.setInterval幾乎是你唯一的朋友。

如何使用setTimeout遞歸調用設置另一個超時是如下

function go() { 
    if (go.count < 4) { 
     // logs 1, 2, 3 to firebug console at 1 second intervals 
     console.log(go.count++); 
     window.setTimeout(go, 1000); 
    } 
} 
go.count = 1; 

go(); 

您可以選擇捕捉與window.clearTimeout使用timeoutID如果你需要清除超時之前的功能的例子它完成。

請注意,window.setTimeoutwindow.setInterval都不會阻止其他腳本的執行 - 我不認爲這是JavaScript的可行方式。有些方法可能會被編碼以模仿UI阻塞,例如使用showModalDialog或者一些全球性的blocking布爾值,這些布爾值大概就像您可能會遇到的一樣。

+4

這已經是問題:) – 2010-06-28 23:10:45

+1

-1:它已經在問題中。世界衛生組織提高了這一點? – naiad 2010-06-28 23:11:31

+1

是真的,這是問題所在,但它幾乎是對'Thread.Sleep()'/'插入語言等效'的JavaScript答案。 – 2010-06-28 23:13:39

9

@俄羅斯凸輪是正確的,setTimeout是你在找什麼。然而,您在問題中提到的方式讓我覺得可能會對使用方式造成一些困惑。

它不會阻塞它所在塊的執行,而是會在一定的時間間隔後調用它的輸入函數。作爲一個例證:

function illustration() { 
    // start out doing some setup code 
    alert("This part will run first"); 

    // set up some code to be executed later, in 5 seconds (5000 milliseconds): 
    setTimeout(function() { 
    alert("This code will run last, after a 5 second delay") 
    }, 5000); 

    // This code will run after the timeout is set, but before its supplied function runs: 
    alert("This will be the second of 3 alert messages to display"); 
} 

您將看到三個警報消息,當您運行該功能,與第二和第三之間的延遲:

  1. 「這部分將首先運行」
  2. 「這將3的警報消息的第二顯示」
  3. ‘此代碼將最後運行,延遲5秒’
+0

是的,我明白,但我想阻止執行,所以setTimeout沒有幫助。 – nomind 2010-06-29 11:33:09

+1

如果你想阻止執行,那麼'while'是你想要的,但是這會凍結瀏覽器(因爲它阻止執行)。我懷疑你真的想阻止執行。 – pkaeding 2010-06-29 14:16:32

3

後這個答案可能有點煩人,但是裸露在外:-)。

由於JavaScript通常在瀏覽器中運行,該瀏覽器是多線程的,其中的JavaScript可能佔用多個線程,因此沒有像在單線程程序中那樣使用「全局睡眠」的概念。

如果您想以任何合理的方式暫停操作,您可能需要考慮以下事項。

比方說,你需要將以下

function foo(s) { 
    var j = 1; var k = 1; 
    sleep(s); // This would be nice right? 
    window.alert("Sum is : " + (j+k)); 
} 

實際上就變成了:

function foo(s) { 
    var j = 1 ; var k = 1; 
    setTimeout(s, function() { 
      window.alert("Sum is : " + (j+k)); 
    }); 
} 

當然,問題是,在一個程序意義上,你可能需要有像

function foo() { 
    do stuff; 
    pause(); 
    do more stuff; 
    return; 
} 

function bar() { 
     foo(10); 
     window.alert("I want this to happen only after foo()"); 
} 

問題是,你不能使用setTimeout來做到這一點,如上所示

但是你可以這樣做:

function foo(s, afterwards, afterparms) { 
    var j = 1 ; var k = 1; 
    setTimeout(s, function() { 
      window.alert("Sum is : " + (j+k)); 
      afterparms.parm1 = afterparms.parm1.toUpperCase(); 
      afterwards(afterparms); 
    }); 
} 

function bar() { 
     foo(10, function() { 
      window.alert("This will happen after window.alert"); 
     }, { parm1: 'hello', parm2: 'world' }); 
} 

請注意,上面只有一個去了解信息傳遞給函數的方式,如果你看看函數調用約定,你可以做一些很酷的東西,可變參數等等

如果您在程序上思考,這很煩人。不過,關於JavaScript有兩點需要記住。它不是一種程序語言,NOR是一種面向對象的語言。 Javascript是一種具有複雜事件管理模型的功能語言。所以你必須用這些術語來思考。

它也是有道理的,因爲典型的JavaScript機器是一個gui(網絡瀏覽器),它在設計時並不想在處理某些東西時完全阻塞。想象一下,當一個頁面正在做某件事情時,你的瀏覽器完全鎖定了,你想要掐死那個給你的程序員。

Javascript代碼應該是'遺忘'性質的,如果事情在繼續之前必須等待事件發生,那麼您應該查看javascript事件模型。

雖然這是不方便的編程,當你想要做一些微不足道的事情時,你有可能使用暫停等待的方式,可能會遇到競爭條件開始,並有一個更合適的方式去你試圖實現的「效果」。

如果您發佈您的PARTICULAR案件,可能會有更多信息即將出現,以瞭解如何解決此類情況。

乾杯,

+0

錯了。 JS不運行多線程。 setTimeout也不會做問題的要求。詳情請參閱我的回答。 – selfawaresoup 2010-06-29 07:31:51

+0

JavaScript是單線程的。許多瀏覽器也是如此。 – 2010-06-29 07:36:24

+0

我很感謝你的意見。我用我的用例更新了這個問題,如果這證明需要sleep()。 – nomind 2010-06-29 11:46:36

3

我可以做一個window.showModalDialog並把window.close在模態對話框與的setTimeout的非常小的時間

這是創造性的,但它只允許用戶與模態對話框中的任何事物進行交互,持續時間爲開放。瀏覽器的其餘部分仍然掛起,就好像你剛剛稱爲一個殘酷的while (new Date().getTime()<t1);循環。

模式對話框對CPU週期更爲友善,並且在等待時間較長的情況下可以避免觸發腳本執行時監視程序,但是您必須在干擾分散的閃爍打開對話框的情況下平衡這一點,和非通用瀏覽器支持,以及每個人都討厭模態對話的問題!

這將會像睡一小段時間,如果需要,我可以多次調用。有沒有其他的方法?

你究竟想通過睡覺實現什麼?無需返回到事件循環或觸發模式對話框,您將不會獲得任何屏幕更新或用戶交互,所以我沒有看到內聯睡眠將爲您做什麼。你當然不能這樣做動畫。

在Firefox中,您可以獲得Python風格的generators,這將允許您編寫使用yield的過程式交互過程,以根據需要將控制權返回給瀏覽器。這可以提高代碼的簡單性,因爲您不必將條件和循環結構重寫爲變量中的記憶狀態。然而,由於只有Mozilla瀏覽器支持它,所以在可預見的將來,你無法真正使用它。

ETA:

我想寫與同步API的ORM,使開發人員可以更輕鬆地使用它。爲了彌合這種異步同步api,我需要睡眠。

對不起,一般情況下無法做到。基本的JavaScript沒有線程,協程或其他可以橋接同步和異步代碼的原語。

Web SQL數據庫規範依賴於瀏覽器調用您的結果處理函數(傳遞給executeSql())作爲瀏覽器回調。瀏覽器回調只能在控制傳遞迴瀏覽器時觸發,而不在同步執行線程內。

在理論上,你可以打開一個modalDialog,做異步Web SQL數據庫調用modalDialog的窗口,並有modalDialog結果返回到調用程序窗口的腳本代碼同步。但是,目前還沒有支持openDatabaseopenModalDialog的瀏覽器!

+0

如果需要,請參閱更新問題中的用例。但是我的showModalDialog方法存在問題,即使我在10ms內關閉它,它可能會顯示在慢機器上(這是可能的嗎?),焦點不會回到父窗口中的正確位置。 – nomind 2010-06-29 12:00:56

+0

@nomind:添加了無用的信息。也許如果未來的瀏覽器一起實現模式對話框和SQL,這可能是可行的,但是同時也會出現閃爍窗口的問題,這需要用戶禁用彈出窗口攔截器。我想你將不得不忍受異步代碼和回調函數。或者只是使用更廣泛支持的同步'localStorage'後端而不是異乎尋常的'openDatabase':對於具有對象風格訪問的'小型webapp',關係數據庫的特性根本無法幫到你。 – bobince 2010-06-29 12:45:31

+0

我不同意。任何基於webkit的瀏覽器如google chrome都有showModalDialog和openDatabase – nomind 2010-06-29 22:12:49

6

澄清:問題是要在一段時間內完全停止腳本執行,而不是延遲某段代碼的執行,這些代碼可能是setTimeout或setInterval的任務。

sleep()的乾淨實現是不可能的,在JavaScript中也是不可取的。

setTimout和setInterval不會停止腳本執行,就像這裏似乎有些人認爲頂部想法一樣。剛剛註冊一個要運行的功能推遲。當超時/間隔正在等待時,腳本的其餘部分將繼續運行。

由於JavaScript的異步特性,「阻止」任何代碼執行的唯一方法是非常醜陋且絕對不推薦的while循環運行一段給定的時間。由於JavaScript本身運行在一個單獨的線程中(我們並不是在這裏討論WebWorkers API ......)。這將停止運行任何JS代碼,直到該循環結束。但是這真的是不好的風格...

如果你的程序不能沒有像睡眠()一樣的工作,也許你應該重新思考你的方法。

1

我知道這個問題有點舊,但我有一個類似的問題,我需要模擬一個花費很長時間加載頁面的腳本。我最終通過創建一個等待5秒的服務器端端點來解決問題,然後發送響應,然後向DOM添加一個腳本標記指向此目標。

授予它需要一個服務器端實現,但是,它允許您在任何特定點停止頁面。正如其他人之前所說,這將阻止整個瀏覽器,而不僅僅是你的腳本。