2017-07-08 237 views
1

我認爲我對setTimeout在JavaScript中的確有些誤解。我有這樣的腳本:setTimeout在Node.js中等待時間過長

function recursiveFibonacci(n) { 
    if (n === 0) { 
     return 1; 
    } else if (n === 1) { 
     return 1; 
    } else { 
     return recursiveFibonacci(n-1) + recursiveFibonacci(n-2); 
    } 
} 

setTimeout(() => {console.log("one second");}, 1000); 

console.log(recursiveFibonacci(42)); 

我會希望發生的是,recursiveFibonacci開始隆隆走在斐波那契序列的第43值。我的電腦需要4秒左右的時間。於是,下班後1秒的評價將被中斷,控制檯將日誌:

one second 

,然後在約3秒後登錄:

433494437 

相反發生的事情是,在4秒鐘後,控制檯日誌:

433494437 
one second 

所有一次。爲什麼會這樣?我怎樣才能讓setTimeout工作?是否是這樣的情況:JavaScript解釋器實際上並未被setTimeout中斷,而是如果它完成其他作業那麼它將在調用給定函數之前等待已經過去給定的時間量?

編輯:

,我發現這個工具非常有用的理解相關概念:

Loupe

+1

'setTimeout'是一個函數,它將在給定的時間內並行(幾乎)與其他正在運行的代碼一起執行一個命令。你似乎對延遲更感興趣,比如'$ .delay()'函數。是的,翻譯不會中斷。 – Mikael

+0

@Mikael,'$'沒有在節點中定義。我應該輸入什麼來使用它? – SeanLetendre

+0

jQuery。在JavaScript上下文中'''通常意味着jQuery,抱歉不會更清楚。祝你好運。 – Mikael

回答

6

的Javascript中的Node.js是事件驅動和單線程的。由於你的reverseFibonacci()函數是同步的,它不允許其他任何東西運行,直到完成。

因此,即使定時器觸發並且定時器回調被放入內部nodejs事件隊列,JS解釋器也不能進入事件隊列中的下一個事件,直到您的reverseFibonacci()函數完成。

setTimeout()不會中斷當前正在運行的Javascript。相反,它將事件放入事件隊列中,噹噹前正在運行的Javascript完成時,JS解釋器將把下一個事件從事件隊列中拉出並運行。

所以,在你的場景事件的順序是這樣的:

  1. 日程安排,從現在1秒計時器事件。
  2. 開始運行reverseFibonacci()
  3. 定時器在1秒鐘後觸發(在nodejs中),並將事件插入到nodejs事件隊列中。
  4. 4秒後,您的reverseFibonacci(42)完成運行。
  5. 由於當前運行的JS已經完成,JS解釋器將下一個事件從事件隊列中拉出並處理它,導致您的定時器回調最終被調用。

setTimeout()在計劃時間後儘快運行計時器,但如果Javascript解釋器忙於運行其他代碼,它們不會中斷該代碼。定時器系統將事件放入事件隊列中,當其他代碼完成時,則Javascript解釋器將下一個事件從事件隊列中拉出並運行(您的計時器回調將被調用)。

1

這是因爲你的函數做同步工作。

node event loop的性質是異步的。至於你的功能完成執行或者你會執行一些異步 - nextTick將被調用。最有可能的第一個項目將是你setTimout函數。

這裏的例子與預期同步塊,和它的作品如您所願:

function sleep(ms) { 
    return new Promise((resolve, reject) => { 
    setTimeout(resolve, ms); 
    }); 
} 

async function recursiveFibonacci(n) { 
    await sleep(10); 
    if (n === 0) { 
     return 1; 
    } else if (n === 1) { 
     return 1; 
    } else { 
     return await recursiveFibonacci(n-1) + await recursiveFibonacci(n-2); 
    } 
} 

setTimeout(() => {console.log("one second");}, 1000); 

recursiveFibonacci(25).then(console.log);