2019-11-18-本周學(xué)習(xí)周報

學(xué)習(xí)總覽

JavaScript

  • 運行機制
    • 渲染引擎
    • JavaScript引擎
    • 調(diào)用棧
    • 事件循環(huán)

CSS

  • 盒模型的理解

HTML

  • HTML語義化

學(xué)習(xí)內(nèi)容

(1)JavaScript運行機制

談?wù)劸€程問題

JavaScript是一門單線程運行的語言。那么為什么JavaScript是單線程呢?我們可以假設(shè)JavaScript是多線程的,線程1和線程2并行,線程1刪除了DOM節(jié)點A,線程2卻要修改DOM節(jié)點A,那么當(dāng)線程2操作該節(jié)點的時候我們到底該怎么處理呢?這種不確定性導(dǎo)致我們必須保證DOM的狀態(tài)是唯一的,所以JavaScript變成了一門單線程語言。

同步異步

既然都說了JavaScript是單線程的,那么必然就會存在執(zhí)行內(nèi)容擁堵的情況,例如最常見的網(wǎng)絡(luò)請求,當(dāng)請求發(fā)給后端的時候,我們是不會等到數(shù)據(jù)回來再執(zhí)行接下來的代碼的,所以任務(wù)執(zhí)行就分成了兩種:

  • 同步任務(wù)
  • 異步任務(wù)

當(dāng)主線程遇到同步任務(wù)時會直接執(zhí)行,并且這些同步任務(wù)的執(zhí)行會形成一個執(zhí)行棧,而當(dāng)主線程碰到異步任務(wù)的時候,異步任務(wù)會暫時性地被跳過,讓主線程接著去執(zhí)行接下來其他的同步任務(wù),當(dāng)那些暫時被跳過的異步任務(wù)有了結(jié)果,就會立即被推進一個任務(wù)隊列(task queue),等到主線程空出來后,主線程會主動去檢查這個任務(wù)隊列,看里面都有什么內(nèi)容等待執(zhí)行,然后依次執(zhí)行即可,這里有一個很關(guān)鍵的點,如果我們寫了兩個平行關(guān)系的ajax請求,那么這兩個異步請求的回調(diào)誰先執(zhí)行是不確定的,原因就是異步請求誰先進入任務(wù)隊列的順序在沒有經(jīng)過限制(例如promise的then回調(diào)限制)的情況下是不確定的。
說了這么多,我們還是放個圖來直觀感受一下吧:


JS執(zhí)行過程.png

宏任務(wù)/微任務(wù)

在了解宏任務(wù)和微任務(wù)的特點之前,我們只需要記住一句話,在當(dāng)前微任務(wù)沒有完成之前,是不會執(zhí)行下一個宏任務(wù)的。
微任務(wù)、宏任務(wù)與Event-Loop一文中,作者借助銀行辦理業(yè)務(wù)的隊伍形象地解釋了宏任務(wù)和微任務(wù)的差別,我提煉了作者傳達出的兩個要點:

  • 微任務(wù)的任務(wù)隊列不為空時,主線程是不會去執(zhí)行宏任務(wù)隊列中的宏任務(wù)的
  • 在不同的運行環(huán)境下宏/微任務(wù)的種類有細微差別

在瀏覽器以及node環(huán)境下,宏任務(wù)和微任務(wù)列表如下:


宏任務(wù).png

微任務(wù).png

我們結(jié)合上面兩個表格來看一段代碼:


carbon-宏_微任務(wù).png

我大致繪制了一個流程如下:


流程.jpg

回調(diào)隊列

回調(diào)隊列也稱為事件隊列或者消息隊列,本身就是用于幫助Web API模塊處理異步操作的。在Web API模塊中,異步操作在相應(yīng)的線程中處理完成得到結(jié)果之后,會把結(jié)果注入異步回調(diào)函數(shù)的參數(shù)中,并且把回調(diào)函數(shù)推入回調(diào)隊列中。
雖然我們將異步操作的結(jié)果推入了回調(diào)隊列中,但什么時候?qū)⑦@些結(jié)果拿給主線程調(diào)用棧去執(zhí)行呢?這就要說到事件循環(huán)了。

回調(diào)隊列
隊列是一個FIFO,先進先出的存儲結(jié)構(gòu),
這樣意味著異步操作的回調(diào)函數(shù)會按照進入隊列的順序被執(zhí)行,而不是調(diào)用的順序被執(zhí)行。

事件循環(huán)(Event Loop)

事件循環(huán)所做的事情就是不斷不斷在主線程調(diào)用棧與回調(diào)隊列中之間來回檢查,首先檢查主線程調(diào)用棧是否為空了,如果為空就去回調(diào)隊列中拿取第一個任務(wù)放入調(diào)用棧,依次循環(huán),直到調(diào)用棧以及回調(diào)隊列都為空。

借助一道面試題小試牛刀

在搜集資料的過程中,我發(fā)現(xiàn)了一道頻繁出現(xiàn)的頭條面試題,在體現(xiàn)JavaScript運行機制與運行順序這兩個知識點上很有代表性,代碼如下:


carbon-執(zhí)行機制筆試題.png

上面這段代碼的運行結(jié)果,我們事先給出來:


carbon-運行機制筆試題結(jié)果.png

首先需要補充一下ES6中關(guān)于async函數(shù)的內(nèi)容。
待完善

(2)CSS盒模型

在前端頁面中,元素會被渲染成一個一個的矩形區(qū)域,而渲染的依據(jù)就是CSS盒模型(basic box model)。每一個盒子由四個部分組成,內(nèi)容區(qū)域、內(nèi)邊距區(qū)域、邊框區(qū)域以及外邊距區(qū)域。

盒模型.png

內(nèi)容區(qū)域通常放著元素真實的內(nèi)容,如文本、圖像或者播放器等。
內(nèi)邊距區(qū)域與內(nèi)容區(qū)域相鄰,負責(zé)擴展內(nèi)容區(qū)域的背景,填充在內(nèi)容區(qū)域與邊框之間。
邊框區(qū)域與內(nèi)邊距區(qū)域相鄰,是容納邊框的區(qū)域。
外邊距區(qū)域與邊框區(qū)域相鄰,可以將相鄰的元素相互分隔開(這里時常會出現(xiàn)邊距融合的現(xiàn)象)。

在CSS發(fā)展的過程中,出現(xiàn)了兩種盒模型,W3C標(biāo)準(zhǔn)盒模型以及怪異盒模型。這兩種盒模型的主要差異在于對于渲染的元素塊的尺寸計算不同。

在W3C標(biāo)準(zhǔn)盒模型中,width以及height指定的寬高就是內(nèi)容區(qū)域的實際寬高,真正的盒子寬高計算就變成了

realWidth = width + padding寬度 + border寬度
realHeight = height + padding高度 + border高度

在怪異盒模型中,我們設(shè)置的width/height就是盒子的寬高,真實的內(nèi)容區(qū)域的寬度是width減去padding以及border的寬度后的結(jié)果,高度算法相同。

雖然W3C標(biāo)準(zhǔn)盒模型是公開的標(biāo)準(zhǔn),但是它并不好用,相反微軟堅持使用的IE怪異盒模型在開發(fā)中體驗十分友好。舉一個典型的例子:假設(shè)一行有四個盒子,每一個盒子有1px寬的邊框,按照標(biāo)準(zhǔn)盒模型,每一個盒子給出25%的寬度,四個盒子并不能并行排列在一行,而按照怪異盒模型,每一個盒子的寬度會被設(shè)置為25%,其內(nèi)容寬度則是在25%盒子寬度的基礎(chǔ)上減去2px的邊框?qū)挾群蟮玫降慕Y(jié)果,無論我們?nèi)绾卧O(shè)置邊框?qū)挾榷疾粫绊戜秩緣K的寬度,這就體現(xiàn)了怪異盒模型的好處。這么一看標(biāo)準(zhǔn)也未必都是完美的,所以為了靈活地在兩個模式下切換CSS中提供了box-sizing去設(shè)置border-box屬性值讓我們可以在某一個確定的元素上使用怪異模式去計算寬高。

前文介紹margin外邊距的時候,我們提到了一個外邊距融合的問題,這個現(xiàn)象是怎么產(chǎn)生的呢?我們假設(shè)元素塊A的外邊距是20px,而元素B的外邊距是30px,前面也提到外邊距是用來分隔相鄰元素的,那么我們是不是只要保證當(dāng)前塊和相鄰塊之間的間距大于等于我們設(shè)置的值就可以了,我們給這個值起個名字叫做最小安全距離,所以元素A和元素B之間我們會取到其中一個較大的值,這個值就是最小安全距離。所以我們給出的這個例子最終A和B之間的距離會是30px。
解釋完為什么會出現(xiàn)外邊距融合后,我們還需要了解一點外邊距融合只會在垂直方向上發(fā)生,即marginTop和marginBottom融合,水平方向的margin是不會融合的,大致情況如圖:


橫向的margin不融合.png

根據(jù)MDN的說法,margin的合并大致會有以下幾種場景:

  • 相鄰元素之間
  • 父元素與第一個以及最后一個元素之間
  • 空的塊級元素自身

首先,我們來理一下第一種情況,前文提到過margin合并只會出現(xiàn)在垂直方向,在這里補充一點margin合并還僅發(fā)生在塊級元素上,甚至不包括行內(nèi)塊級元素,所以這里所謂的相鄰指的就是兩個相鄰的塊級元素。
[圖片上傳失敗...(image-129f27-1574575972909)]

第二種情況如下圖所示,當(dāng)我們給子元素設(shè)置上邊距和下邊距時,時常會發(fā)現(xiàn)我們并沒有將子元素和父元素之間擠出一段空隙,反而將父元素一塊向下頂了一段距離出來。


上邊界的margin合并.png

下邊界的margin合并.png

第三種情況就比較抽象了,我繪制了一個示例,如下圖:


空元素的margin合并現(xiàn)象.png

實際上第三種情況,簡單理解就是當(dāng)一個元素是空塊(無高度、無內(nèi)容、無border/padding)的時候,它本身的上下margin會合并在一起,上下兩個Margin值誰大取誰。

(3)HTML語義化

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,684評論 1 32
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口,提供良好的抽象接口。 管理調(diào)度進程,并將多個進程對硬件...
    drfung閱讀 3,776評論 0 5
  • 進程和線程 多線程可以并行處理任務(wù),但是線程是不能單獨存在的,它是由進程來啟動和管理的。 一個進程就是一個程序的運...
    oWSQo閱讀 1,078評論 0 1
  • 本文用來介紹 iOS 多線程中 GCD 的相關(guān)知識以及使用方法。這大概是史上最詳細、清晰的關(guān)于 GCD 的詳細講...
    花花世界的孤獨行者閱讀 581評論 0 1
  • 今天的晨讀讓我想起一句話:完成比完美更重要。 以前寫晨讀感悟時總想把每一個點都寫好,但總是寫不好,有時候?qū)ψ约簺]有...
    紫翼天葵閱讀 309評論 0 0

友情鏈接更多精彩內(nèi)容