前端面試:js同步與非同步問題

solvep發表於2019-03-31

前端面試:js同步與非同步問題

前言

我本來是打算寫一篇co原始碼精讀(為啥讀co,因為它短),然鵝發現自己存在一系列基礎問題沒有搞透徹,打算寫一個js基礎系列文章,總結自己的理解(copy),希望與你在學習路上一同進步。首先問問自己當面試官問到js中的同步和非同步,這個問題該怎麼回答?理解一個問題無非是what-why-how js同步和非同步問題是什麼-->為什麼會產生非同步問題-->如何解決。

一、JavaScript起源

技術的出現,和應用場景密切相關的。JavaScript誕生於1995年。當時,它的主要目的是處理以前由伺服器端語言(如Perl)負責的一些輸入驗證操作。在JavaScript問世之前,必須把表單資料傳送到伺服器端才能確定使用者是否沒有填寫某個必填域,是否輸入了無效的值。Netscape Navigator希望通過JavaScript來解決這個問題。起初名字為livescript,但是後來Netscape(網景)與Sun公司成立了一個開發聯盟。Netscape為了搭上媒體熱炒Java的順風車,臨時把LiveScript改名為JavaScript,所以從本質上來說JavaScript和Java沒什麼關係(趁熱度)。 如今,JavaScript的用途早已不再侷限於簡單的資料驗證,而是具備了與瀏覽器視窗及其內容等幾乎所有方面互動的能力。今天的JavaScript已經成為一門功能全面的程式語言

總結:js最初的用途是為來實現使用者與瀏覽器的互動

二、JS為何是單執行緒的?

JavaScript的單執行緒,與它的用途有關。作為瀏覽器指令碼語言,JavaScript的主要用途是與使用者互動,以及操作DOM。這決定了它只能是單執行緒,否則會帶來很複雜的同步問題。比如,假定JavaScript同時有兩個執行緒,一個執行緒在某個DOM節點上新增內容,另一個執行緒刪除了這個節點,這時瀏覽器應該以哪個執行緒為準?

所以,為了避免複雜性,從一誕生,JavaScript就是單執行緒,這已經成這門語言的核心特徵,將來也不會改變。

注:所謂單執行緒,是指在JS引擎中負責解釋和執行JavaScript程式碼的執行緒只有一個。

三、計算機的同步與非同步(重點)

計算機領域中的同步(Synchronous)和非同步(Asynchronous)和我們生活中的同步和非同步的概念是恰好相反的,感覺是翻譯要背這個鍋。生活中的同步,突出的是‘同’,相同的步伐,是我們倆一起行動,比如一起去逛街吃飯飯睡覺覺。非同步則是你忙你的,我忙我的,步調不致且互不干擾。難到計算機裡的同步和非同步不是這樣?確實不是。

"計算機的同步"就好比:你去外地上學人生地不熟,突然生活費不夠了;此時你決定打電話回家,通知家裡轉生活費過來,可是當你撥出電話時,對方一直處於待接聽狀態(即:打不通,聯絡不上),為了拿到生活費,你就不停的oncall、等待,最終可能不能及時要到生活費,導致你今天要做的事都沒有完成,而白白花掉了時間。

"計算機的非同步"就是:在你打完電話發現沒人接聽時,猜想:對方可能在忙,暫時無法接聽電話,所以你發了一條簡訊(或者語音留言,亦或是其他的方式)通知對方後便忙其他要緊的事了;這時你就不需要持續不斷的撥打電話,還可以做其他事情;待一定時間後,對方看到你的留言便回覆響應你,當然對方可能轉錢也可能不轉錢。但是整個一天下來,你還做了很多事情。或者說你找室友臨時借了一筆錢,又開始happy的上學時光了。

總結:計算機中的同步就是排隊等待,假如你是第一百零一個備胎,那你只能等前面的一百個爆了之後才能‘處理’你。非同步就是,儘管你是第一百零一個,她還是能照顧到你的感受。

四、js單執行緒為什麼會有'非同步'問題

看完前面的鋪墊你是否會產生這些疑問,JS是單執行緒的,那麼他是如何是實現非同步操作的?AJAX非同步傳送和回撥請求,還有setTimeout也看起來像是多執行緒的?不急慢慢來

  • js是同步的?

是的,單執行緒,那肯定只能同步(排隊)執行咯

  • js為什麼需要非同步?

如果JS中不存在非同步,只能自上而下執行,萬一上一行解析時間很長,那麼下面的程式碼就會被阻塞。 對於使用者而言,阻塞就意味著"卡死",這樣就導致了很差的使用者體驗

  • js單執行緒又是如何實現非同步的呢?

通過事件迴圈(event loop) 實現'非同步'

經典問題:

 console.log('1')
setTimeout(function(){
 console.log('2')
},0)
console.log('3')  
//       1,3,2
複製程式碼

也就是說,setTimeout裡的函式並沒有立即執行,而是延遲了一段時間,滿足一定條件後,才去執行的,這類程式碼,我們叫非同步程式碼。

所以,這裡我們首先知道了JS裡的一種分類方式,就是將任務分為: 同步任務和非同步任務

前端面試:js同步與非同步問題

雖然JS是單執行緒的但是瀏覽器的核心是多執行緒的,在瀏覽器的核心中不同的非同步操作由不同的瀏覽器核心模組排程執行,非同步操作會將相關回撥新增到任務佇列中。而不同的非同步操作新增到任務佇列的時機也不同,如 onclick, setTimeout, ajax 處理的方式都不同,這些非同步操作是由瀏覽器核心的 webcore 來執行的,webcore 包含上圖中的3種 webAPI,分別是 DOM Binding、network、timer模組。

按照這種分類方式:JS的執行機制是

  • 首先判斷js程式碼是同步還是非同步,同步就進入主程式,非同步就進入event table
  • 非同步任務在event table中註冊函式,當滿足觸發條件後,被推入event queue
  • 同步任務進入主執行緒後一直執行,直到主執行緒空閒時,才會去event queue中檢視是否有可執行的非同步任務,如果有就推入主程式中 以上三步迴圈執行,這就是event loop

總結:同步可以保證順序一致,但是容易導致阻塞;非同步可以解決阻塞問題,但是會改變順序性,根據不同的需要去寫你的程式碼。

每週都會持續更新,您的點贊,收藏,關注三連擊是我的動力,決定了前方的路怎麼走,就不要總回頭看,peace&love。

相關文章