只有掌握了 N-1 層的原理,才能精通第 N 層的抽象
-- 佚名
複製代碼
視工做類型而定,有時候想掌握 N-1 層的原理,可能還須要瞭解 N-2,N-3 ...javascript
於前端程序員而言,第 N 層的抽象即 HTML/CSS/JS 語法,N+1 層是各類前端框架,N-1 層是語法的內部實現和瀏覽器的工做原理,N-2 層可能就是渲染引擎,JS 引擎,JS Runtime的實現。html
你見過沒有掌握 HTML/CSS/JS 卻精通 React 框架的人麼?前端
本文只談 HTML ,要想真正的精通 HTML ,咱們須要知道 HTML 的內部實現,通讀 HTML 規範是最有效的方法之一html5
經過本文,咱們想要達到的目的有:java
PS: 本文描述中的 「標準」 和 「規範」 指的是同一東西程序員
PS2: 爲何要看 HTML 規範?一般 API 文檔只告訴了咱們要這麼作,卻沒告訴咱們爲何不能這樣作,經過看規範,咱們能對 API 理解更加深入web
首先明確一點, MDN 不是規範文檔,確切的說法是指南和開發教程,是對規範的二次解讀。 相比規範,MDN 在行文格式和專業術語的運用上更容易讓前端開發者接受。大部分狀況下,MDN 已可以解決問題。當發現 MDN 上的解釋不夠清晰時,這時候就能夠去看規範了。通常這種狀況,都是比較深刻底層的問題,畢竟,規範是用來給瀏覽器開發者看的。算法
Web 平臺的瀏覽器相關技術衆多,由不一樣的組織來肯定規範。 早在以前,關於 HTML 和 DOM 標準, W3C 和 WHATWG 都有各類的規範,這嚴重阻礙了 HTML 的發展。chrome
W3C 但願發佈一個 finished 版本的 HTML5,而 WHATWG 想要不斷維護該規範而不是將已知問題凍結在某個版本canvas
不過現在兩個組織已達成一致,HTML 和 DOM 標準由 WHATWG 維護。
關於一項技術,如何肯定對應的規範並找到規範文檔,這裏推薦一個網站:The Web platform: Browser technologies 。 其列舉了 Web 平臺的瀏覽器相關技術的標準文檔和協議規範地址,包括如下幾大模塊:
頁面上用圖標指出了各個技術規範的制定組織,以及在 caniuse 和 MDN 中的地址,同時給出了該項技術的使用建議--理解使用/謹慎使用
細心的同窗能夠發現,WebSocket API
等技術和 HTML 都是定義在同一規範文檔 html.spec.whatwg.org/multipage/ 中,這個後文會說緣由
咱們知道 html 是一種超文本標記語言,因此 HTML 規範指的是 html(包括文檔,元素和語法) 的編碼規範?
不是, HTML 規範 != HTML 編碼規範 。HTML 規範是對包括 html 語言在內的多種技術的規範定義,是瀏覽器開發者必須遵循的標準,並提供上層接口供頁面開發者使用。
The HTML Standard is a kitchen sink full of technologies for the web. It includes the core markup language for the web, HTML, as well as numerous APIs like Web Sockets, Web Workers, localStorage, etc.
HTML 規範是多種 Web 技術的集合。它包括用於 Web 的核心標記語言 HTML 以及 Web Sockets, Web Workers, localStorage 等衆多API。相對於其餘規範,它在 Web 平臺的技術規範中的位置總結以下:
狹義上來講, HTML5 定義 HTML 標準的最新的版本,所以本文也能夠說是 HTML5 標準
廣義上來講, HTML5 泛指現代 Web 技術,包括本文所定義的標準外,還有其餘如 Notifications API
, WebRTC
等等
相關的還有 h5 這個名詞,在國內偏向於指代移動端的 web 頁面的解決方案
本節介紹 HTML 規範的總體結構。
對於每一小節,會先介紹主體內容,而後列出相關技術點方便之後查找,可能還會給出注意事項
先上目錄:
須要重點看的有:7,8
介紹本規範的結構,提供閱讀說明及排版。
簡單介紹了跨站通訊和html的編寫以及常見的語法錯誤
提供了用於發現 HTML 錯誤的工具 -- HTML Conformance Checkers
提供了術語說明和依賴的定義
規則中依賴的其餘規範的定義都會在本節作個概要描述
case-sensitive
表示區分大小寫的字符串比較
定義了策略控制功能,如 autoplay, document-domain
定義了常見的 microsyntaxes ,一些語法類型的問題能夠看這裏
HTML 中有不少地方接受特定的數據類型,如日期和數字,本節描述了對應類型內容應符合的標準,以及如何解析
定義了 URL ,描述瞭解析過程,以及 base URLs 變更後的效果
僅表層介紹,具體的須要調整至 URL 規範中查看
定義了資源獲取,包括同/跨域類型定義,資源類型肯定,meta 元素字符編碼提取過程,CORS 設置屬性,referrer 屬性,nonce 屬性
定義了通用 DOM 接口,包括 IDL 屬性獲取和設置,HTMLCollection 等集合接口,DOMStringList 接口,Document 的垃圾回收
定義告終構化數據,包括可序列化對象和可傳輸對象等
這一小節屬於比較底層了
介紹了 HTML 文檔的生命週期,一個 HTML 文檔表現爲一個 Document 對象,其上有各類屬性如元數據管理,DOM 樹訪問器,動態標記插入,用戶交互及 onreadystatechange
關於 Document, HTML 標準在 DOM 標準之上進行了拓展
enum DocumentReadyState { "loading", "interactive", "complete" };
typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[OverrideBuiltins]
partial interface Document {
// resource metadata management 資源元數據管理
[PutForwards=href, Unforgeable] readonly attribute Location? location;
attribute USVString domain;
readonly attribute USVString referrer;
attribute USVString cookie;
readonly attribute DOMString lastModified;
readonly attribute DocumentReadyState readyState;
// DOM tree accessors DOM 樹訪問器
getter object (DOMString name);
[CEReactions] attribute DOMString title;
[CEReactions] attribute DOMString dir;
[CEReactions] attribute HTMLElement? body;
readonly attribute HTMLHeadElement? head;
[SameObject] readonly attribute HTMLCollection images;
[SameObject] readonly attribute HTMLCollection embeds;
[SameObject] readonly attribute HTMLCollection plugins;
[SameObject] readonly attribute HTMLCollection links;
[SameObject] readonly attribute HTMLCollection forms;
[SameObject] readonly attribute HTMLCollection scripts;
NodeList getElementsByName(DOMString elementName);
readonly attribute HTMLOrSVGScriptElement? currentScript; // classic scripts in a document tree only
// dynamic markup insertion 動態標記插入
[CEReactions] Document open(optional DOMString unused1, optional DOMString unused2); // both arguments are ignored
WindowProxy? open(USVString url, DOMString name, DOMString features);
[CEReactions] void close();
[CEReactions] void write(DOMString... text);
[CEReactions] void writeln(DOMString... text);
// user interaction 用戶交互
readonly attribute WindowProxy? defaultView;
boolean hasFocus();
[CEReactions] attribute DOMString designMode;
[CEReactions] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
boolean queryCommandEnabled(DOMString commandId);
boolean queryCommandIndeterm(DOMString commandId);
boolean queryCommandState(DOMString commandId);
boolean queryCommandSupported(DOMString commandId);
DOMString queryCommandValue(DOMString commandId);
// special event handler IDL attributes that only apply to Document objects
// 只適用於 Document 對象的特殊事件處理器 IDL 屬性
[LenientThis] attribute EventHandler onreadystatechange;
// also has obsolete members
};
Document includes GlobalEventHandlers;
Document includes DocumentAndElementEventHandlers;
複製代碼
經過了解這個,咱們能更清楚的知道文檔的組成,對 document 屬性有疑問的均可以看本節
介紹了 HTML 元素,規則僅表示含義,不涉及呈現,所以各個瀏覽器呈現出來的特定元素效果可能不同。
HTML 元素的基本接口
[Exposed=Window]
interface HTMLElement : Element {
[HTMLConstructor] constructor();
// metadata attributes 元數據屬性
[CEReactions] attribute DOMString title;
[CEReactions] attribute DOMString lang;
[CEReactions] attribute boolean translate;
[CEReactions] attribute DOMString dir;
// user interaction 用戶交互
[CEReactions] attribute boolean hidden;
void click();
[CEReactions] attribute DOMString accessKey;
readonly attribute DOMString accessKeyLabel;
[CEReactions] attribute boolean draggable;
[CEReactions] attribute boolean spellcheck;
[CEReactions] attribute DOMString autocapitalize;
[CEReactions] attribute [TreatNullAs=EmptyString] DOMString innerText;
ElementInternals attachInternals();
};
HTMLElement includes GlobalEventHandlers;
HTMLElement includes DocumentAndElementEventHandlers;
HTMLElement includes ElementContentEditable;
HTMLElement includes HTMLOrSVGElement;
[Exposed=Window]
interface HTMLUnknownElement : HTMLElement {
// Note: intentionally no [HTMLConstructor]
// 注意:有意沒有 [HTMLConstructor]
};
複製代碼
介紹了 HTML 命名空間中名稱爲 name 的元素的元素接口的確認規則
舉例: xmp 元素原型是什麼? 答案是 HTMLPreElement (繼承自 HTMLElement )
介紹了元素構造器用於實現自定義元素
定義了內容模型,即每一個 HTML 元素的內容(其 DOM 中的子節點)必須符合內容模型的要求
舉例
<p><object><param><ins><map><a href="/">Apples</a></map></ins></object></p>
爲了檢查 a 元素中是否容許 "Apples",要檢查內容模型。 a 元素的內容模型是透明的,map 元素也是, ins 元素也是,object 元素中 ins 元素所在的部分也是。 object 元素位於 p 元素中,後者的內容模型是 短語內容。 所以 "Apples" 是容許的,由於文本是短語內容。
介紹了通用屬性,全部 HTML 元素均可以使用,如 contenteditable,style,title,dir,lang
介紹了 innerText
的執行步驟
每一個元素都有一個預約義的含義,本章便解釋了這些含義。 也給出了做者使用這些元素的規則,以及用戶代理處理這些元素的要求。 這裏包含了大量的 HTML 獨有的特性,例如視頻播放和副標題,表單控件和表單提交, 以及名爲 HTML canvas 的 2D 圖形 API。
有具體元素使用上的疑問能夠在本章中查找
本標準介紹了爲文檔增長機器可讀註解的機制,這樣工具能夠從文檔中抽取鍵值對的樹。 這部分文檔描述了該機制和用於將 HTML 文檔轉換爲其餘格式的一些算法。 這部分還爲聯繫信息、日曆事件和許可協議定義了一些示例的微數據詞彙。
itemscope 上的使用有疑問,先看 MDN 再看本章
HTML Document 能夠提供一些用戶與內容交互以及用戶修改內容的機制,在本章中給出了這些機制的描述。
提供了 hidden 屬性的描述
display: block 能夠覆蓋 hidden 的效果
描述了惰性子樹的概念
舉個常見的例子,在A元素中 mouseDown 而後移動到 B 元素上並 mouseUp ,mouseMove 和 click 事件是在A元素上觸發,B 是惰性的
描述了焦點的工做機制
這裏的處理挺複雜的
描述了用於激活元素的指定快捷鍵 -- accesskey
描述了可編輯元素的相關接口和 API:contenteditable, designMode, execCommand, inputmode
描述了元素拖拽的相關接口和處理過程,其中部分章節是非規範的,因此瀏覽器間的實現會有差別
這部分定義了不少影響處理多頁面環境的特性。要深刻理解瀏覽器的運行過程,本章節須要細讀。
描述了瀏覽上下文的定義和分類,包括嵌套瀏覽上下文(iframe)和輔助瀏覽上下文(window.opener)
描述了 Window, WindowProxy, 和 Location 對象的安全基礎設施
這裏介紹了 window.open 等方法的執行機制
介紹了 Origin 的定義和同源判斷算法,以及 document.domain
賦值描述
介紹了沙盒機制(sandboxing)
介紹了會話歷史和導航接口: history 和 location
描述了瀏覽上下文導航和頁面加載處理模型
描述了離線應用緩存。
這部分介紹了 HTML 應用腳本的基本特性。也是須要重點細讀的章節
介紹了腳本,包括 javascript: URL
,啓用禁用腳本,腳本處理模型,Event Loops 和瀏覽器事件
Event Loops 一節還講述了和渲染引擎的交互
介紹了 WindowOrWorkerGlobalScope mixin,描述了全局對象上公開的 API
typedef (DOMString or Function) TimerHandler;
interface mixin WindowOrWorkerGlobalScope {
[Replaceable] readonly attribute USVString origin;
// base64 工具方法
DOMString btoa(DOMString data);
ByteString atob(DOMString data);
// timers
long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);
void clearTimeout(optional long handle = 0);
long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments);
void clearInterval(optional long handle = 0);
// microtask queuing
void queueMicrotask(VoidFunction callback);
// ImageBitmap
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options);
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options);
};
Window includes WindowOrWorkerGlobalScope;
WorkerGlobalScope includes WindowOrWorkerGlobalScope;
複製代碼
其中介紹了 Base64 工具方法 , Timers 執行過程,microtask 和 ImageBitmap 處理
介紹了動態標記插入
萬惡的 document.write
介紹了用戶提示窗口方法: alert,confirm,prompt 的內部處理和 print 打印機提示方法
能夠了解這些方法執行時再事件循環中的處理是怎樣的
介紹了系統狀態和功能 Navigator ,描述了基本功能接口和自定義方案處理程序
所以瀏覽器能夠經過自定義方案處理程序拓展功能,如 geo , gamepads
最後介紹了動畫幀,定義了 requestAnimationFrame 和 cancelAnimationFrame
這部分描述了 HTML 編寫的應用可用來與同一客戶端中的,不一樣域名的其餘應用通訊的一些機制。 也介紹了一個服務器推送事件流機制,稱爲 Server Sent Events 或 EventSource, 以及一個爲腳本提供的雙向全雙工套接字協議,稱爲 Web Sockets。
首先介紹了繼承自 Event 的 MessageEvent 接口,本章介紹的事件消息都是基於 MessageEvent 接口
介紹了服務器發送的事件,引入了 EventSource 接口定義和實現
介紹了 Web sockets 的組成和內部處理
引入了 postMessage 跨文檔通訊,用來解決非同源文檔間通訊問題,且不會形成跨站腳本攻擊
介紹了 MessageChannel 通道用來實現不一樣瀏覽上下文之間代碼通訊
最後介紹了向其餘瀏覽上下文廣播的方案 BroadcastChannel
這部分定義了 JavaScript 後臺線程的 API。
描述了一些使用場景,如數字密集型計算,共享 worker
描述了做用域和事件循環
描述了可用的 API
這部分定義了一個基於鍵值對的客戶端存儲機制。
定義了咱們經常使用的 API: localStorage 和 sessionStorage 以及 storage 事件
二者的區別是 sessionStorage 在瀏覽器關閉後內容會消失
描述了 storage 的可用磁盤空間,不過標準沒有給出具體值,只是建議每一個域 5M 的限制(未壓縮前)
描述了 storage 的隱私和安全問題
本章描述有 HTML MIME type 標註的資源的語法規則
介紹了文檔的組成部分,包括 DOCTYPE 和 Elements 類型。描述了標籤和屬性的解析規則
描述了 HTML 文檔解析的處理模型,包括錯誤處理,輸入字節流,解析狀態,Tokenization 和樹結構等
從圖中也可看出 html 解析和腳本執行的關係
腳本執行會阻塞 DOM 的解析,試想下,不阻塞的話,腳本中修改了 DOM 那還得調整原來構建的 DOM 樹
描述了 HTML 片斷的序列化和解析
本章描述 XML 資源的語法規則,主要是描述 XML 文檔的解析,以及 XML 片斷的序列化和解析
這部分定義了 Web 瀏覽器默認的渲染規則。
注意,本章僅是建議,沒有要求瀏覽器必須這樣實現
所以,各類渲染引擎的效果不同是按規範來
本章更多的是講元素的預期渲染效果,渲染引擎機制請看 Event Loops 一節
包括三部分
這部份內容比較針對瀏覽器開發者
本章主要描述使用資源類型和協議時的一些注意事項
下面代碼分別輸出什麼,爲何?請從瀏覽上下文和事件循環等角度分析。
function onClick1(){
window.open('https://www.baidu.com')
console.log("onClick1")
}
function onClick21(){
location.href = "https://www.baidu.com"
console.log("onClick21")
}
function onClick22(){
location.href = "https://www.baidu.com"
// 3s
let start = +new Date
while(+new Date - start< 3*1000){}
console.log("onClick22")
}
function onClick23(){
// 未能加載成功的網站
location.href = "https://sssss"
// 3s
let start = +new Date
while(+new Date - start< 3*1000){}
console.log("onClick23")
}
function onClick3(){
history.back()
// 3s
let start = +new Date
while(+new Date - start< 3*1000){}
console.log("onClick3")
}
複製代碼
onClick21 onClick23 onClick3 會輸出
僅以 chrome 的實現爲例,每一個標籤頁都是獨立的用戶代理(user agent)
首先,頁面 A 存在着(至少)一個瀏覽上下文,並對應着一個 Event Loop
考慮嵌套瀏覽上下文和輔助瀏覽上下文,因此這邊用的是至少
頁面 A 中執行了某段同步代碼(一個Task),在其中調用了 window.open 方法,該方法是當即執行的
內部作了不少處理,能夠點連接看看
執行完畢 ,此時會建立一個新的瀏覽上下文以及對應的 Event Loop
若是 頁面 A 採用 opener 參數打開的頁面 B,則頁面 B 還有一個輔助瀏覽上下文,指向頁面 A 的瀏覽上下文,共用同一個 Event loop??
若是要加載的文檔是 html ,頁面 B 的用戶代理會排一個 Task 建立 Document 對象,標記爲 HTML 文檔,其後讀取和解析文檔。
location 跳轉
location 是同步執行的,後臺線程等解析完文檔就會跳轉,不會等後面的同步代碼。一般咱們後面的同步代碼很快執行,因此會誤覺得 location 是異步執行的
詳見 stackoverflow 和 設置location.href,爲何不會當即跳轉? - 知乎
PS: 還沒詳細看規範,不知道是否是這樣處理
history 跳轉是一個 Task,所以它會在本次同步代碼執行完畢後才執行
這個看運行時環境實現,可能其餘任務還會先與該 Task 前執行
總結: window.open
和 location.href
不屬於 Web API 的範疇,也就不走 event loop 那一套
未完待續...