2015-05-28 26 views
0

我是新的(2天!!)JavaScript的世界,我唯一的編碼經驗是Java語言執行順序發生。 我明白,或者至少我已經讀過JavaScript是異步的,這意味着如果有一個語句需要很長時間才能執行,那麼執行下一條語句時不會阻止第一條語句的程序。 我遇到過回調(其實很多!!),但我看不出它們如何被用來確定執行順序。我寫了一段代碼只是爲了瞭解它是如何完成的,我當然可以使用一些幫助。如何在涉及異步調用時設置執行的特定順序?

console.log("Beginning"); 

function Test(callback){ 
    setTimeout(function(callback){ 
     console.log("Something that takes a lot of time"); 
    },5000); 
    callback(); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 

Test(tstCallBack); 

我要的是輸出到顯示 -

Beginning 
Something that takes a lot of time 
Should come last 

但我得到的輸出 -

Beginning 
Should come last 
Something that takes a lot of time 

有什麼我可以做的就是在輸出我想要的方式?

+0

「JavaScript是異步的,這意味着如果有一個聲明需要很長時間才能完成xecute,下一個語句執行時不會阻止第一個語句的程序。「這是錯誤的,javascript的異步陳述是真實的,但這不是因爲一個函數需要很長時間,線程會自動進一步跳轉,這取決於它是否是異步函數。 Btw Java在最近的版本中可以是異步的,但它不太常見。 –

+0

@NexusDuck - 非常感謝你!這是我錯過的。也就是說(如果我錯了,糾正我),JavaScript具有這些內置功能,這些功能很容易導致/或者導致延遲,並且這些功能是異步的以避免問題;這意味着我們無法自定義製作我們自己的異步函數(不依賴於內置的東西) 我是對的嗎? – Savvy

+0

你是對的,看看@ jfriend00的回答,他有一個更詳細的版本(重要的一點是,JavaScript具有更異步的本質,因爲它是單線程的,而Java可以是多線程的) –

回答

2

讓我們澄清一些事情你所說:

我是新(2天!)到JavaScript和我唯一的現有技術的編碼 經驗的世界是在Java中,語句的執行發生 。我明白,或者至少我讀過,JavaScript 是異步的,這意味着如果有一條語句需要很長時間才能執行,則執行下一條語句時不會將第一條語句的程序保存爲 。

這不是它的工作原理。給定的函數可以是異步的,也可以是按設計同步的。它與執行需要多長時間完全沒有關係。您可以擁有非常快速的異步功能或非常長的同步功能。什麼決定了函數是否是異步的是它的設計。如果它使用異步I/O或定時器或任何其他異步基礎架構,那麼至少某些函數的執行是異步的。這意味着一些函數將在完成後執行,並且在該函數調用之後的一些代碼將在異步部分完成之前執行。

我遇到了回調(其實很多!!),但我看不到他們如何使用 來確定執行順序。我寫了一段 代碼只是爲了瞭解它是如何完成的,我肯定可以使用一些 的幫助。

回調函數用於在某些異步操作完成時通知調用代碼。這可以用來消耗異步操作的結果,也可以用來執行下一段想要在異步操作完成後依次運行的代碼。

在你的代碼示例中,如果你想要所需的序列,那麼你必須調用setTimeout()回調中的回調,以便在setTimeout()調用執行後被調用,從而爲您提供所需的序列。

您還必須將callback參數移除到setTimeout回調。該回調沒有通過該參數傳遞,因此聲明它是錯誤的。它可以直接從通過關閉父功能如下所示進行訪問:

console.log("Beginning"); 

function Test(callback){ 
    setTimeout(function(){ 
     console.log("Something that is asynchronous"); 
     // call the callback here to indicate to the calling code 
     // that the asynchronous operation is now complete 
     callback(); 
    },5000); 
    console.log("After Setting Timer"); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 

Test(tstCallBack); 

這將產生的控制檯序列:

開始

設置定時器

異步的東西

應該最後一次


概念,JavaScript引擎運行的單個線程和單線程使用事件隊列。所以,在你上面的函數中,這是發生了什麼。

  1. 第一console.log("Beginning");被執行。
  2. Test(tstCallback)被調用。
  3. 作爲執行Test()函數的一部分,計劃了一個計時器。這注冊了JS引擎的內部定時器。
  4. 繼續執行Test()中的代碼,執行console.log("After Setting Timer");,然後該函數結束。
  5. JS執行的當前線程結束了,如果事件隊列中沒有其他東西,那麼JS引擎就無事可做了,但是等待下一個事件發生。
  6. 一段時間後(定時器設置的5秒鐘),內部定時器會觸發,並將定時器事件放入JS事件隊列中。
  7. 由於此刻沒有其他JS正在執行,因此計時器事件將從事件隊列中拉出並執行。這意味着調用了爲該計時器註冊的原始回調。
  8. 由於定時器回調被調用,它將執行console.log("Something that is asynchronous");行,然後調用callback()
  9. 然後調用您的tstCallback函數並執行console.log("Should come last");
  10. 異步事件完成執行,JS引擎查看事件隊列中是否有更多事件。如果是這樣,則將下一個事件從隊列中拉出並運行。

有JavaScript的如何處理異步操作的數量非常好的參考:

How does JavaScript handle AJAX responses in the background?

How Javascript Timers Work

Do I need to be concerned with race conditions with asynchronous Javascript?

+0

雖然沒有必要把回調作爲setTimeout的函數的參數,但它可以在函數內由於關閉而訪問 –

+0

@NexusDuck - 你是對的,我修好了。 – jfriend00

+0

@ jfriend00 - 我終於明白了...謝謝你sooo !!你從很多苦難中拯救了我,希望我有了代表upvote .. – Savvy

0

廣場內setTimeout回調,而不是外界稱爲callback將第一的setTimeout之前執行不作爲的JavaScript不會等待setTimeout執行(as JS is synchronous by nature)和執行的下一行,因此你不會得到期望的輸出。

console.log("Beginning"); 
function Test(callback){ 
    setTimeout(function(){ 
    console.log("Something that takes a lot of time"); 
    callback(); 
    },5000); 
} 
function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 

Demo

1

很多你所說的話是錯誤的。 JavaScript的順序與Java相同,但異步調用更頻繁。如果您希望在長時間之後調用回調,則必須在長時間運行的程序之後調用它。像這樣 -

console.log("Beginning"); 
function Test(callback){ 
    setTimeout(function(callback){ 
    console.log("Something that takes a lot of time"); 
    callback(); 
    },5000); 

} 
function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 
+1

The第二次調用回調,應該在Test函數裏面去掉。 – wonderbell

+0

@aSharma確實 - 我甚至沒有注意到它是誠實的。 –

+0

非常感謝,但我知道這樣做的特殊方式。我想也許還有其他的一些方法。我仍然不明白回調的意義,雖然:( – Savvy

0

我已經修改了您的代碼,如下所示,以獲得所需的輸出。

console.log("Beginning"); 
function Test(callback){ 

    console.log("Something that takes a lot of time"); 
    setTimeout(callback,5000); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 

的setTimeout需要將在指定的時間間隔

使用的setTimeout的是異步部分之後執行的回調函數。當執行上述代碼時,首先打印「開始」控制檯語句,然後調用Test函數傳入一個函數,該函數需要在500ms後異步執行。

相關問題