答:我平時喜歡研究一些網站,並對一些技術的原理和好玩的點感興趣,我本身也喜歡思考,也喜歡嘗試探索有沒有更好的方式和實現。(有所收留,不要所有說出來,稍微留一點懸念留做面試官來提問)javascript
答:適當自信,向本身擅長的方向上面來引路;要讓面試官來欣賞我,而不是來鄙視他。css
(豁達自信,適當收住),巧妙演示實例,適時討論疑問(不知道的問題請求指導一下,如何去解決,不要說不知道,或者不瞭解)html
切忌小聰明(儘可能把問題的全部實現方法都寫出來,表現出來的是熟練)前端
[!NOTE]
> 1. 方向要對,過程要細(性能優化,過程詳細)
> 2. 膽子要大、心態要和(算法題認真思考,認真使勁想;勇於承擔責任,不要輕易放棄)html5
1.已知寬高java
/*v1*/ .container { position: absolute; left: 50%; top: 50%; marigin-left: -width / 2; marigin-top: -width / 2; } /*v2*/ .container { position: absolute; top: calc(50% - 5em); left: calc(50% - 9em); }
2.未知寬高web
/*v1*/ .container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } /*v2:flex+ auto*/ .wrapper { dislay: flex; } .content { margin: auto; } /*v3. 父元素居中*/ .wrapper { display: flex; /* 盒子橫軸的對齊方式 */ justify-content: center; /* 盒子縱軸的對齊方式 */ align-items: center; } /*v4.body內部居中*/ .content { /* 1vh = 1% * 視口高度 */ margin: 50vh auto; transform: translateY(-50%); }
/* 網格佈局 */ .wrapper { display: grid; width: 100%; grid-template-columns: 300px 1fr 300px; }
[!NOTE]
知道transition 過渡動畫和animation 關鍵幀動畫區別和具體實現。面試
- 1.CSS動畫實現輪播圖
- 2.CSS動畫實現旋轉的硬幣
- 3.CSS動畫實現鐘擺效果
IE盒子模型:width = content + pading + borderajax
box-sizing : border-box算法
解決方案:對父級元素建立BFC
[!NOTE]
BFC: 塊級格式化上下文,IFC(內聯格式化上下文)
<section id="margin"> <style> #margin { background-color: #4eff35; overflow: hidden; } #margin>p { /*上 左右 下*/ margin: 5px auto 25px; background-color: #ff255f; } </style> <p>1</p> <!--把一個元素放在一個容器裏面,爲這個容器建立BFC便可解決邊距重疊問題--> <div style="overflow: hidden"> <p>2</p> </div> <p>3</p> </section>
<section id="layout"> <style> #layout { background-color: #48adff; } #layout .left { float: left; height: 300px; width: 200px; background-color: #ff4344; } #layout .right { height: 400px; background-color: #ff255f; /*給右邊的這個盒子容器建立一個BFC, 這個容器裏面的內容就會沿着垂直方向延伸*/ overflow: auto; /*overflow: auto;*/ /*display: table;*/ /*float: left;*/ /*position: fixed;*/ } </style> <div class="left"> LEFT </div> <div class="right"> RIGHT <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> <p>111</p> </div> </section>
<section id="float"> <style> /*一個盒子內部的內容若是是浮動的話,那麼這個盒子的內容其實是不參與父容器高度計算的*/ #float { background-color: red; /*overflow: hidden;*/ float: left; } #float .float { float: left; font-size: 30px; } </style> <div class="float"> 我是浮動的元素 </div> </section>
[!NOTE]
DOM級別一共能夠分爲四個級別:DOM0級、DOM1級、DOM2級和DOM3級。而DOM事件分爲3個級別:DOM0級事件處理,DOM2級事件處理和DOM3級事件處理。
瀏覽器爲當前的頁面與用戶進行交互的過程當中,點擊鼠標後事件如何傳入和響應的呢?
什麼樣的事件能夠用事件委託,什麼樣的事件不能夠用呢?
[!NOTE]
- 一般支持事件冒泡(Event Bubbling)的事件類型爲鼠標事件和鍵盤事件,例如:mouseover, mouseout, click, keydown, keypress。
- 接口事件(指的是那些不必定與用戶操做有關的事件)則一般不支持事件冒泡(Event Bubbling),例如:load, change, submit, focus, blur。
很明顯:focus 和 blur 都屬於不支持冒泡的接口事件。既然都不支持冒泡,那又如何實現事件代理呢?
IE採用冒泡型事件 Netscape使用捕獲型事件 DOM使用先捕獲後冒泡型事件
[!NOTE]
IE DOM cancelBubble = true stopPropagation() // 中止冒泡 returnValue = false preventDefault() // 阻止元素默認事件 srcEelement target // 事件目標
window -> document -> HTML標籤 -> body -> ... -> 目標元素
[!NOTE]
關鍵點: 注意根節點是window這個對象的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="container"> <style> #container { width: 200px; height: 200px; background-color: #ff255f; } </style> </div> <script> // 事件捕獲機制 window.addEventListener('click', function(){ console.log('window capture'); }, true) document.addEventListener('click', function () { console.log('document capture'); }, true) document.documentElement.addEventListener('click', function () { console.log('HTML capture'); }, true) document.body.addEventListener('click', function () { console.log('body capture'); }, true) document.getElementById('container').addEventListener('click', function () { console.log('container capture'); }, true) // 事件冒泡機制 window.addEventListener('click', function(){ console.log('window capture'); }) document.addEventListener('click', function () { console.log('document capture'); }) document.documentElement.addEventListener('click', function () { console.log('HTML capture'); }) document.body.addEventListener('click', function () { console.log('body capture'); }) document.getElementById('container').addEventListener('click', function () { console.log('container capture'); }) // 輸出結果 window capture --> document capture --> HTML capture --> body capture --> container capture --> container capture --> body capture --> HTML capture --> document capture --> window capture </script> </body> </html>
var html = document.documentElement;
document.documentElement.onclick = function(e) { console.log(e.currentTarget, e.target); // <html><body>...</body></html>()給綁定事件的那個元素, 當前被點擊的那個元素 }
[!NOTE]
e.target : 當前被點擊的元素,父元素使用事件代理的方式來實現,能夠直接使用該屬性獲取被點擊的那個元素
// v1. 使用Event對象來自定義事件 // 開始建立一個本身定義的事件對象 var eve = new Event('customEvent'); // 使用dom2事件處理的方式來給這個元素綁定一個事件 var dom = document.documentElement; dom.addEventListener('customEvent', function(e) { console.log('customEvent called!'); }); // 下面的這句話能夠在適合的場景中來觸發一個本身定義的事件對象 setTimeout(function(){ // 在1s以後觸發這個事件 dom.dispatchEvent(eve); }, 1000) // v2. 使用CustomEvent來實現自定義事件 var dom = document.documentElement; // 使用CustomEvent的方式能夠在事件觸發的時候傳遞一個參數,而後經過e.detail 的方式來獲取這個參數信息 var myClick = new CustomEvent('myClick', {detail : {name : 'zhangsan', age : 24}}); dom.addEventListener('myClick', function(e){ console.log(e.detail, e.target) }) dom.dispatchEvent(myClick);
[!NOTE]
HTTP協議採用‘請求-應答’模式, HTTP1.1版本才支持的,使用Keep-alive字段能夠創建一個長鏈接,從而不須要每次請求都去創建一個新的鏈接。
// 1. 使用字面量的方式來建立 var o1 = {name : 'zhangsan'}; var o11 = new Object({name : 'zhangsan'}); // 2. 使用普通構造函數的方式來建立 var M = function(){ this.name = 'zhangsan'; } var o2 = new M(); // 3. Object.create方法 var p = {name : 'zhangsan'}; var o3 = Object.create(p);
構造函數:使用new運算符來聲明一個實例(任何函數都是能夠經過構造函數來使用的)
原型鏈:經過原型鏈能夠找到上一級別的原型對象
原型對象:多個實例公用的數據和屬性或者方法
[!NOTE]
instanceof 檢測一個對象A是否是另外一個對象B的實例的原理是:查看對象B的prototype指向的對象是否在對象A的[[prototype]]鏈上。若是在,則返回true,若是不在則返回false。不過有一個特殊的狀況,當對象B的prototype爲null將會報錯(相似於空指針異常)。
// 2. 使用普通構造函數的方式來建立 var M = function(){ this.name = 'zhangsan'; } var o2 = new M(); undefined o2.__proto__ == M.prototype true o2.__proto__ == M.prototype true o2.__proto__.constructor === Object false o2.__proto__.constructor === M true
// new 一個對象的過程 var _new = function (fn) { // 1. 建立一個對象,這個對象要繼承fn這個構造函數的原型對象 var o = Object.create(fn.prototype); // 2. 執行構造函數 var k = fn.call(o, arguments); // 3. 看下執行的這個函數的運行效果是否是函數 if (typeof k === 'object'){ return k; } else { return o; } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> // 類的聲明 function Animal1() { this.name = 'name'; } // ES6 中的class的聲明 class Animal2 { constructor(){ this.name = 'name'; } } console.log(new Animal1(), new Animal2()); /////////////////////////////////////////////////////////////////////////////////////////// // 如何實現類的繼承呢???-----------本質:原型鏈 // v1. 藉助構造函數實現繼承 function Parent1() { this.name = 'parent1' } Parent1.prototype.sayHello = function () { console.log('hello'); } function Child1() { // 執行父親的構造函數: // 1. 實現原理:將父級函數的this指向了這個子類的實例上面去了 // 2. 缺點:父親的原型鏈上面的方法或者屬性不能被繼承;只能實現部分繼承 Parent1.call(this); this.type = 'child1'; } // 沒有參數的時候,能夠直接new + 函數名稱 console.log(res = new Child1); // v2. 藉助原型鏈實現繼承 function Parent2() { this.name = 'parent2'; this.data = [1, 2, 3]; } Parent2.prototype.sayHello = function () { console.log('hello'); } function Child2() { this.type = 'child2'; } // prototype 就是爲了讓這個對象的實例能夠訪問到原型鏈上的內容 Child2.prototype = new Parent2(); // new Child2().__proto__ === Child2.prototype // true // new Child2().__proto__.name // parent2 // 原型鏈繼承的缺點: // 1. 原理:經過修改原型鏈來實現對象的繼承關係 // 2. 缺點:修改第一個對象上面的屬性,會直接修改第二個對象屬性數據(引用類型) var c1 = new Child2(); var c2 = new Child2(); c1.data.push(100, 200, 300); // v3. 組合繼承 function Parent3() { this.name = 'parent3'; this.data = [1, 2, 3]; } function Child3() { // 1. 借用構造函數繼承 Parent3.call(this); this.type = 'child3'; } // 2. 原型鏈繼承 // child3的原型對象是Parent3的一個實例對象,可是這個實例對象中是沒有constructor這個屬性的,所以尋找屬性的時候回沿着這個實例對象的原型鏈繼續向上尋找new Parent3().prototype 這個原型對象的, // 最終在Parent3.prototype這個原型對象中找到了這個屬性,new一個對象找的其實是{Parent3.prototype.constructor : Parent3} Child3.prototype = new Parent3(); var c1 = new Child3(); var c2 = new Child3(); c1.data.push(100, 200, 300); // 組合繼承的特色: // 1. 原理:結合借用構造函數繼承和原型鏈繼承的優勢,摒棄兩者的缺點 // 2. 缺點:父類構造函數在建立實例的時候總共執行了兩次(new Parent3(), new Child3()) // v4. 組合繼承的優化1 function Parent4() { this.name = 'parent4'; this.data = [1, 2, 3]; } function Child4() { // 1. 借用構造函數繼承 Parent4.call(this); this.type = 'child4'; } // 讓子類的構造函數的原型對象和父類構造函數的原型對象執向同一個對象(都是同一個對象) Child4.prototype = Parent4.prototype; // 測試 var c1 = new Child4(); var c2 = new Child4(); console.log(c1 instanceof Child4, c1 instanceof Parent4); console.log(c1.constructor) // Parent4? 如何實現:c1.constructor(c1.__proto__.constructor) === Child4 呢? // 缺點: // 1. 沒法經過原型對象的constructor屬性來獲取對象的屬性對應的構造函數了(子類和父類公用的是一個contructor) // 2. obj instanceof Child4 === true; obj instanceof Parent4 === true // 3. obj.__proto__.constructor === Child4; obj.__proto__.constructor === Parent4 ??? // v5. 組合繼承的優化2【完美寫法】 function Parent5() { this.name = 'parent5'; this.data = [1, 2, 3, 4, 5]; } function Child5(){ Parent5.call(this); this.type = 'child5'; } // 經過建立中間對象的方式來把兩個對象區分開 // var obj = new Object(); obj.__proto__ = Constructor.prototype; // 1. Object.create建立的對象obj, 這個obj的原型對象就是參數 // 2. Child5的原型對象是Child5.prototype // 3. Child5.prototype = obj,obj這個對象至關於就是一箇中間的橋樑關係 Child5.prototype = Object.create(Parent5.prototype); // 當前的方式仍是會按照原型鏈一級一級向上尋找的, 給Child5的原型對象上面綁定一個本身定義的constructor屬性 Child5.prototype.constructor = Child5; // var s1 = new Child5() // 上面的代碼等價於 var obj = Object.create(Parent5.prototype); // obj.prototype = Parent5.prototype Child5.prototype = obj; Child5.prototype.constructor = Child5; // 1. 對象之間就是經過__proto__ 屬性向上尋找的 // 2. 尋找規則: child5 ---> Child5.prototype ---> obj(Object.create(Parent5.prototype)) ---> Parent5.prototype // 技巧:不要讓面試官問太多題目:拖拉時間【擠牙膏】,把一個問題儘可能吃透 // 消化這一塊內容 </script> </body> </html>
[!WARNING]
面試技巧
[!NOTE]
同源策略限制是從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。(一個源的文檔或腳本是沒有權利直接操做另一個源的文檔或腳本的)
function ajax(params){ // 1. 建立對象,考慮兼容性【重點】 var xhr = XMLHTTPRequest ? new XMLHTTPRequest() : new window.ActiveXObject('Microsoft.XMLHTTP'); // *** 兼容性問題必須考慮 // 2. 打開鏈接 var type = params.type || 'GET', url = params.url || '', data = params.data || {}, success = params.success, error = params.error, dataArr = []; for (var k in data) { dataArr.push(k + '=' + data[k]); } //帶上Cookie xhr.withCredentials = true; if (type.toUpperCase() === 'GET') { // get url += '?' + dataArr.join('&'); // 問號結尾的話,直接替換爲空字符串 xhr.open(type, url.replace(/\?$/g, ''), true); // GET 請求的話,是不須要再send方法中帶上參數的 xhr.send(); } else { // POST xhr.open(type, url, true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); // POST 請求須要把數據放在send方法裏面, data = name=zhangsna&age=18&sex=male xhr.send(dataArr.join('&')); } // 開始監聽變化 xhr.onreadystatechange = function(){ // 這裏須要考慮強緩存和協商緩存的話直接處理,206是媒體資源的建立方式 if (xhr.readyState === 4 && xhr.status === 200 || xhr.status === 304) { var res; if (success instanceof Function) { res = xhr.responseText; if (typeof res === 'string') { res = JSON.parse(res); // 開始執行成功的回調函數 success.call(xhr, res); } } else { if (error instanceof Function) { // 失敗的話直接返回這個responseText中的內容信息 error.call(xhr, res); } } } } }
function jsonp(url, onsuccess, onerror, charset){ // 1. 全局註冊一個callback var callbackName = 'callback' + Math.random() * 100; window[callbackName] = function(){ if (onsuccess && typeof onsuccess === 'Function') { onsuccess(arguments[0]); } } // 2. 動態建立一個script標籤 var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); charset && script.setAttribute('charset', charset); script.setAttribute('src', url); script.async = true; // 3. 開始監聽處理的過程 script.onload = script.onreadystatechange = function(){ if (!script.readyState || /loaded|complete/.test(script.readyState)) { // 4. 成功以後移除這個事件 script.onload = script.onreadystatechange = null; // 刪除這個script的DOM對象(head.removeChild(script), 這個DOM節點的父節點至關因而head標籤這個父節點) script.parentNode && script.parentNode.removeChild(script); // 刪除函數或變量 window[callbackName] = null; } } script.onerror = function(){ if (onerror && typeof onerror === 'Function') { onerror(); } } // 5. 開始發送這個請求(把這個標籤放在頁面中的head標籤中便可) document.getElementsByTagName('head')[0].appendChild(script); }
hash 改變後頁面不會刷新的
[!NOTE]
使用場景:當前的頁面A經過iframe或者frame嵌入了跨域的頁面
// 1. A頁面中的代碼以下 var B = document.getElementsByTagName('iframe'); B.src = B.src + '#' + JSON.stringfy(data); // 2. B中的僞代碼以下 window.onhashchange = function(){ var data = window.location.hash; // 接受數據 data = JSON.parse(data); }
[!NOTE]
使用場景: 能夠實現窗口A(A.com)向窗口B(B.com)發送信息
// 1. 窗口B中的代碼以下 var BWindow = window; BWindow.postMessage(JSON.stringfy(data), 'http://www.A.com'); // 2. 窗口A中代碼 var AWindow = window; AWindow.addEventListener('message', function(e){ console.log(e.origin); // http://www.B.com console.log(e.source); // BWindow e.source.postMessage('已成功收到消息'); console.log(JSON.parse(e.data)); // data }, false) // 父窗口給子窗口發信息,須要用iframe的contentWindow屬性做爲調用主體 // 子窗口給父窗口發的信息須要使用window.top,多層iframe使用window.frameElement
[!NOTE]
不受同源策略影響,能夠直接使用
var ws = new window.WebSocket('ws://echo.websocket.org'); // 打開鏈接 ws.onopen = function(e){ console.log('Connection open ……'); ws.send('Hello WebSocket!'); } // 接受消息 ws.onmessage = function(e){ console.log('Received Message : ', e.data); } // 關閉鏈接 ws.onclose = function(e){ console.log('Connection closed'); }
支持跨域通訊版本的Ajax,是一種新的標準(Origin頭)【ajax的一個變種,適用於任何】
http://www.ruanyifeng.com/blog/2016/04/cors.html
fetch('/get/name', { method : 'get' }).then(function(response){ console.log(response); }).catch(function(err){ // 出錯了;等價於then的第二個參數 }); // 緣由:瀏覽器默認會攔截ajax請求,會根據頭中的origin消息進行判斷處理消息;Origin字段用來講明,本次請求來自哪一個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否贊成此次請求。JSONP只支持GET請求,CORS支持全部類型的HTTP請求。JSONP的優點在於支持老式瀏覽器,以及能夠向不支持CORS的網站請求數據。
Access-Control-Allow-Origin: http://api.bob.com // 必需的字段 Access-Control-Allow-Credentials: true // 可選字段: 是否容許發送cookie Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
CSRF: 跨站請求僞造,Cross site request forgery
XSS: cross-site scripting, 跨站腳本攻擊
攻擊原理: 注入JS腳本
防護措施: 讓JS代碼沒法解析執行
[!NOTE]
[!NOTE]
算法攻略:多刷題纔是硬道理!!!
<!--HTML5的寫法--> <DOCTYPE html> <!-- HTML 4.01 Strict 1. 這個DTD 包含全部的HTML元素和屬性 2. 可是不包含展現性的和棄用的元素(好比font) --> <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" > <!-- HTML 4.0.1 Transitional 1. 這個DTD 包含全部的HTML元素和屬性 2. 也包含展現性的和棄用性的元素(好比font) --> <DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www.w3.org/TR/html4/loose.dtd" >
[!NOTE]
在W3C標準出來以前,不一樣的瀏覽器對頁面渲染有不一樣的標準,產生了必定的差別。這種渲染方式叫作混雜模式。在W3C標準出來以後,瀏覽器對頁面的渲染有了統一的標準,這種渲染方式叫作標準模式。<!DOCTYPE>不存在或者形式不正確會致使HTML或XHTML文檔以混雜模式呈現,就是把如何渲染html頁面的權利交給了瀏覽器,有多少種瀏覽器就有多少種展現方式。所以要提升瀏覽器兼容性就必須重視<!DOCTYPE>
[!NOTE]
嚴格模式和混雜模式都是瀏覽器的呈現模式,瀏覽器究竟使用混雜模式仍是嚴格模式呈現頁面與網頁中的DTD(文件類型定義)有關,DTD裏面包含了文檔的規則。好比:loose.dtd
[!NOTE]
定義:DOM結構中每一個元素都有本身的盒子模型,這些都是須要根據各類樣式來計算並根據計算結果將元素放在它該出現的位置,這個過程就是reflow;
[!NOTE]
定義:當各類盒子的位置、大小以及其餘屬性,例如顏色、字體大小都肯定下來之後,瀏覽器因而便按照元素各自的特性繪製了一遍,因而頁面的內容出現了,這個過程就是repaint
var frag = document.createDocumentFragment(); frag.appendChild(dom); /*每次建立的節點先放入DocumentFragment中*/
document.getElementById("d1").style.cssText = "color:red; font-size:13px;";
[!NOTE]
對於Layout屬性中非引用類型的值(數字型),若是須要屢次訪問則能夠在一次訪問時先存儲到局部變量中,以後都使用局部變量,這樣能夠避免每次讀取屬性時形成瀏覽器的渲染。
var width = el.offsetWidth; var scrollLeft = el.scrollLeft;
[!NOTE]
在元素的position爲static和relative時,元素處於DOM樹結構當中,當對元素的某個操做須要從新渲染時,瀏覽器會渲染整個頁面。將元素的position設置爲absolute和fixed可使元素從DOM樹結構中脫離出來獨立的存在,而瀏覽器在須要渲染時只須要渲染該元素以及位於該元素下方的元素,從而在某種程度上縮短瀏覽器渲染時間。
Layout屬性包括:
看代碼,寫結果?
// 同步任務 console.log(1); // 異步任務要掛起 setTimeout(function(){ console.log(2) }, 0); console.log(3) // out : 1 3 2
console.log('A'); setTimeout(function(){ console.log('B') }, 0); while (true) { } // out : A
for (var i = 0; i < 4; i++) { // setTimeout , setInterval 只有在時間到了的時候,纔會把這個事件放在異步隊列中去 setTimeout(function(){ console.log(i); }, 1000); } // out : 4 4 4 4
[!NOTE]
JS是單線程的,瀏覽器引擎會先來執行同步任務,遇到異步任務以後,會把當前的這個異步任務放在time模塊中,等到主線程中的全部的同步任務所有執行完畢以後;而後當前的這個異步任務只有時間到了以後,纔會把這個任務(回調函數)放在一個異步隊列中;噹噹前的任務棧中的任務所有執行完畢了以後,會先去執行微任務隊列中的任務(Promise),而後等到微任務隊列中的全部任務所有執行完畢以後,再去執行process.nextTick()這個函數,等到這個函數執行完畢以後,本次的事件輪訓結束;
開啓新的執行棧,從宏任務隊列中依次取出異步任務,開始執行;每一個宏任務執行都會從新開啓一個新的任務執行棧
何時向這個任務隊列中放入新的異步任務
理解與放入到異步任務隊列的時機
預解析DNS:DNS Prefetch 是一種DNS 預解析技術,當你瀏覽網頁時,瀏覽器會在加載網頁時對網頁中的域名進行解析緩存,這樣在你單擊當前網頁中的鏈接時就無需進行DNS的解析,減小用戶等待時間,提升用戶體驗。(提早解析域名,而不是點擊連接的時候纔去進行DNS域名解析,能夠節省DNS解析須要耗費的20-120毫秒時間)
<!-- https協議的網站,默認是關閉了DNS的預解析的,可使用下面的語句開啓 --> <meta http-equiv="x-dns-prefetch-control" content="on"> <!-- 開始配置須要進行DNS預解析的域名 --> <link rel="dns-prefetch" href="//www.zhix.net"> <!--支持http和HTTPS--> <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" /> <!--支持http的協議--> <link rel="dns-prefetch" href="http://nsclick.baidu.com" /> <link rel="dns-prefetch" href="http://hm.baidu.com" /> <link rel="dns-prefetch" href="http://eiv.baidu.com" />
var script = document.createElement('script'); document.getElementsByTagName('head')[0].appendChild(script); // 沒有 defer 或 async,瀏覽器會當即加載並執行指定的腳本,「當即」指的是在渲染該 script 標籤之下的文檔元素以前,也就是說不等待後續載入的文檔元素,讀到就加載並執行。 <script src="script.js"></script>
<!-- 有 defer,加載後續文檔元素的過程將和 script.js 的加載並行進行(異步),可是 script.js 的執行要在全部元素解析完成以後,DOMContentLoaded 事件觸發以前完成。 --> <script defer src="myscript.js"></script>
<!-- 有 async,加載和渲染後續文檔元素的過程將和 script.js 的加載與執行並行進行(異步)。 --> <script async src="script.js"></script>
[!NOTE]
- defer是在HTML解析完成以後(DOMContentLoaded事件執行以後)纔會執行,若是是多個,會按照加載的順序依次執行(按照順序執行)
- async是在加載完以後當即執行,若是是多個,執行順序和加載順序無關(與順序無關)
[!NOTE]
緩存目的就是爲了提高頁面的性能
直接從本地讀取,不發送請求
Response Headers cache-control: max-age=315360000(相對時間,優先級比expires高) expires: Sat, 10 Mar 2029 04:01:39 GMT(絕對時間)
問一下服務器,這個文件有沒有過時,而後再使用這個文件
Response Headers last-modified: Tue, 12 Mar 2019 06:22:34 GMT(絕對時間) etag: "52-583dfb6f4de80"
向服務器請求資源的時候,帶上if-Modified-Since或者if-None-Match這個請求頭,去詢問服務器:
Request Headers if-Modified-Since: Tue, 12 Mar 2019 06:22:34 GMT if-None-Match: "52-583dfb6f4de80"
// 方法一:使用try catch捕獲 try { // ... } catch (e) { // error } finally { // handle error } // 方法二:使用window.onerror 捕獲錯誤 // 沒法捕獲到資源加載錯誤 window.onerror = function(msg, url, line, col, error){ // ... } window.addEventListener('error', function(msg, url, line, col, error){ // ... })
// 方法一: 直接在script, img這些DOM標籤上面直接加上onerror事件 Object.onerror = function(e){ // ... } // 方法二:window.performace.getEntries(間接獲取資源加載錯誤的數量) var loadedResources = window.performance.getEntries(); // 1. 獲取瀏覽器中已經加載的全部資源(包括各個階段的詳細加載時間) var loaderImgs = loadedResources.filter(item => { return /\.jpg|png|gif|svg/.test(item.name) }); var imgs = document.getElementsByTagName('img'); // 2. 獲取頁面中全部的img集合 var len = imgs.length - loaderImgs.length; // 3. 加載失敗的圖片數量 console.log('圖片加載失敗數量:', len, '條'); // 方法三: 使用事件捕獲的方式來實現Error事件捕獲 // 使用事件捕獲的方式來實現資源加載錯誤的事件的捕獲:window ---> document --> html --- > body ---> div ---... window.addEventListener('error', function (msg) { console.log(msg); }, true);
// 使用事件捕獲的方式來實現 window.addEventListener('error', function (msg) { console.log('資源加載異常成功捕獲:', msg); }, true); // 使用事件冒泡的方式是隻能捕獲到運行的時候的一些異常 window.addEventListener('error', function (e) { console.log('運行異常成功捕獲1:', e.message, e.filename, e.lineno, e.colno, e.error); }, false); // 這種方式是能夠按照參數的方式來接受相關的參數信息 window.onerror = function (msg, url, line, col, error) { console.log('運行異常成功捕獲2:', msg, url, line, col, error); }
errorinfo : Script0 error 0 row 0 col
<!-- script 表情添加crossorigin屬性 --> <!-- 除了 script,全部能引入跨域資源的標籤包括 link 和 img 之類,都有同樣的屬性 --> <script crossorigin src="http://www.lmj.com/demo/crossoriginAttribute/error.js"></script>
// 服務器能夠直接設置一個響應頭信息 res.setResponseHeader('Access-Control-Allow-Origin', 'www.lmj.com');
// 下面的兩種方式都是能夠實現錯誤信息的上報功能的 (new Image).src = 'http://www.baidu.com?name=zhangsna&age=18&sex=male' (new Image()).src = 'https://www.baidu.com?name=zhangsan'
// IE 瀏覽器提供的獲取電腦硬件的API var locator = new ActiveXObject ("WbemScripting.SWbemLocator"); var service = locator.ConnectServer("."); var properties = service.ExecQuery("SELECT * FROM Win32_Processor");
[!NOTE]
能夠參考性能優化章節-performance性能監控一文內容。
[!NOTE]
[!NOTE]
主要考察點:樂觀積極、主動溝通、邏輯順暢、上進有責任心、有主張,作事果斷、職業競爭力、職業規劃
業務能力:能夠作到行業第一
思考能力:對同一件事能夠從不一樣角度去思考,找到最優解
學習能力:不斷學習新的業務,沉澱、總結
無上限的付出:對於沒法解決的問題能夠熬夜、加班
目標是什麼:在業務上成爲專家,在技術上成爲行業大牛
近階段的目標:不斷的學習積累各方面地經驗,以學習爲主
長期目標:作幾件有價值的事情,如開源做品、技術框架等
方式方法:先完成業務上的主要問題,作到極致,而後逐步向目標靠攏