都是一些很基礎但是很容易被忽略的問題,大家知道這個方法怎麼使用但是並沒有深入研究到底是怎麼一個流程,廢話不多說,看下面的程式碼
<input type="text" value="a" name="input" onkeydown="alert(this.value)" /> <input type="text" value="a" name="input" onkeydown="var me=this;setTimeout(function(){alert(me.value)},0)" >
第一個keydown的時候,彈出來的是input裡原來的value,而第2個在keydown的時候,卻能彈出更新後的value,就是因為setTimeout,雖然他的delay設定為0,幾乎是即時觸發,但還是被加到了執行佇列後面,但就是這個非同步過程,渲染已經完成了,當他回呼函數執行時,輸出來的已經是更新後的value了。這裡還有一個問題是this在不同的function的內部和外部所指示的不同對象的問題,當function裡還有function的時候 多多注意this,很容易出錯誤,細心就好,不多說。
接下來講一下,js js是單線程的,可想而知,如果沒有多線程的話,整個程式就卡死了,幸好瀏覽器是多線程的,瀏覽器使得js具備異步的一些屬性:js是單線程語言,瀏覽器只分配給js一個主線程,用來執行任務(函數),但一次只能執行一個任務,這些任務形成一個任務隊列排隊等候執行,但前端的某有些任務是非常耗時的,例如網路請求,計時器和事件監聽,如果讓他們和別的任務一樣,都老老實實的排隊等待執行的話,執行效率會非常的低,甚至導致頁面的假死。所以,瀏覽器為這些耗時任務開闢了另外的線程,主要包括http請求線程,瀏覽器定時觸發器,瀏覽器事件觸發線程,這些任務是非同步的。
瀏覽器為網路請求這樣的非同步任務單獨開了一個線程,那麼問題來了,這些非同步任務完成後,主線程怎麼知道呢?答案就是回調函數,整個程式是事件驅動的,每個事件都會綁定對應的回呼函數,舉個栗子,有段程式碼設定了一個計時器
setTimeout(function(){ console.log(time is out); },500);
執行這段程式碼的時候,瀏覽器非同步執行計時操作,當500ms到了後,會觸發定時事件,這個時候,就會把回呼函數放到任務佇列裡。整個程式就是透過這樣的一個個事件驅動起來的。
所以說,js是一直是單線程的,瀏覽器才是實現異步的關鍵
以下轉自互聯網:
js一直在做一個工作,就是從任務隊列裡提取任務,放到主執行緒執行。下面我們來進行更深一步的理解。
圖片來自Philip Roberts的演講《Help, I'm stuck in an event-loop》非常深刻!
我們把剛才了解的概念和圖中做一個對應,上文中說到的瀏覽器為非同步任務單獨開闢的線程可以統一理解為WebAPIs,上文中說到的任務隊列就是callback queue,我們所說的主線程就是有虛線組成的那一部分,堆(heap)和棧(stack)共同組成了js主線程,函數的執行就是透過進棧和出棧實現的,比如圖中有一個foo()函數,主執行緒把它推入堆疊中,在執行函數體時,發現還需要執行上面的那幾個函數,所以又把這幾個函數推入堆疊中,等到函數執行完,就讓函數出棧。等到stack清空時,說明一個任務已經執行完了,這時就會從callback queue中尋找下一個人任務推入棧中(這個尋找的過程,叫做event loop,因為它總是循環的查找任務隊列裡是否還有任務)。
相關文章:
相關影片:
以上是(常見面試題)js基礎 從setTimeout 到 js的非同步原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!