前端知識整理,包括html/css/js,但不限於這三大類,持續更新中。
本人水平有限,若有錯誤或更好的答案,歡迎指正,望各位不吝指教。:)javascript
題目:假設高度已知,請寫出三欄佈局,其中左欄、右欄寬度各爲300px,中間自適應
1.浮動佈局
實現方法:左欄、右欄分別左右浮動,定寬300px,中間不設置寬度自適應
缺點:浮動元素脫離文檔流,須要清除浮動,若是處理很差,會致使不少問題(影響先後標籤、父級標籤的位置及 width height 屬性)。
優勢:比較簡單,兼容性比較好。只要清除浮動作的好,是沒有什麼問題的。
2.絕對定位佈局
實現方法:三欄設置絕對定位,左欄 left:0; width:300px,右欄 right:0; width:300px,中間 left:300px; right:300px;
缺點:脫離文檔流,以後的元素也要脫離文檔流。有效性、可以使用性比較差。
優勢:方便快捷,配合js使用方便。
3.flex佈局
實現方法:三欄的父元素 display:flex; 中間 flex:1; 左欄、右欄定寬300px;
優勢:移動端已經大量使用,是css3爲了解決上面兩種方案的缺點而出現,是相對比較完美的方案。
缺點:不能兼容IE8及如下瀏覽器。
4.表格佈局
實現方法:三欄的父元素 display:table; 三欄分別設置 display: table-cell; 左欄、右欄定寬300px;
優勢:用表格佈局實現三欄佈局很簡單就能搞定,兼容性好(兼容IE8),在flex佈局不兼容的時候,能夠嘗試表格佈局。
缺點:有些歷史詬病,只適用部分場景;某個內容撐開了,其餘內容也會跟着撐開,有時候這種效果不是咱們想要的。
5.網格佈局
實現方式:三欄的父元素 display:grid; grid-template-rows:100px; grid-template-columns:300px auto 300px;
網格佈局是新出的一種佈局方式,技術比較新,還未普及,可是也須要咱們掌握。css
三個延伸問題
1.幾種佈局方式的優缺點?
如上html
2.假設把高度去掉,三欄的高度根據內容自適應,那個方案再也不適用,哪一個還能適用?
flex和table還能適用,其他再也不適用。前端
3.兼容性如何,在真實業務中,哪一個方案最實用?
如上,根據使用場景和業務需求,選擇合適的方案。java
題目:有哪些清除浮動的方案?每種方案的優缺點?
題目:談談你對css盒模型的認識?
1.基本概念(標準模型+IE模型)
css 盒模型:margin + border + padding + contentcss3
2.標準模型和IE模型的區別
區別就是高度和寬度的計算方式不一樣
標準模型:width(height) = content
IE模型:width(height) = border + padding + contentweb
3.css如何設置這兩種模型
標準模型:box-sizing: content-box; (瀏覽器默認值)
IE模型:box-sizing: border-box;ajax
4.JS如何設置、獲取盒模型對應的寬和高
(1)dom.style.width/height ,這種方式只能獲取內聯樣式設置的寬和高
(2)dom.currentStyle.width/height ,無論是內聯樣式、<style>標籤寫的樣式、<link>外聯樣式,即獲取渲染後的寬高(僅IE支持)
(3)window.getComputedStyle(dom).width/height ,獲取渲染後的寬高(兼容性更好、通用性更好,chrome/firefox)
(4)dom.getBoundingClientRect().width/height ,獲取渲染後的寬高(計算元素的絕對位置,返回top/left/width/height)chrome
5.根據盒模型解釋邊距重疊
(1)父子元素邊距重疊,取最大值合併
(2)兄弟元素邊距重疊,取最大值合併
(3)空元素上下邊距重疊,取最大值合併json
6.BFC(邊距重疊解決方案)
BFC的基本概念:塊級格式化上下文
BFC的原理(BFC的渲染規則):
(1)在BFC元素的垂直方向的邊距會發生重疊;
(2)BFC的區域不會與浮動元素髮生重疊;
(3)BFC在頁面上是一個獨立的容器,外面的元素不影響裏面,裏面的元素不影響外面;
(4)計算BFC的高度時,浮動元素也會參與計算;(BFC子元素即便是float也會參與高度計算)
如何建立BFC?
(1)float的值不爲none;
(2)position的值不爲static或者relative(能夠設置爲absolute或者fixed);
(3)display:inline-block; 或者table/table-cell等與table相關的屬性
(4)overflow:hidden; overflow:auto;
DOM事件的級別
DOM0 element.onclick = function(){}; // false 爲默認值,表明事件在冒泡階段觸發。設爲true,表明事件在捕獲階段觸發。 DOM2 element.addEventListener('click', function(){}, false); DOM3 element.addEventListener('keyup', function(){}, false);
DOM事件模型
捕獲:由上到下
冒泡:由下到上
DOM事件流
三個階段:(鼠標點擊)-> 捕獲 -> 目標階段 -> 冒泡
DOM事件捕獲的具體流程
window -> document -> html -> body -> ...(父元素) -> 目標元素
document.documentElement === html,冒泡流程則相反
Event對象的常見應用
event.preventDefault(); // 阻止默認行爲 event.stopPropagation(); // 阻止事件冒泡 event.stopImmediatePropagation(); // 元素綁定了多個一樣類型的事件,處理事件優先級 event.currentTarget; // 當前綁定事件的對象 event.target; // 當前被點擊的元素
自定義事件
let ev = document.getElementById('ev'); let eve = new Event('custome'); ev.addEventListener('custome', function () { console.log('custome'); }); ev.dispatchEvent(eve); // new CustomEvent(); // 用法相似Event,傳參不同
事件捕獲流程
window.addEventListener('click', function () { console.log('window captrue'); }, true); document.addEventListener('click', function () { console.log('document captrue'); }, true); document.documentElement.addEventListener('click', function () { console.log('html captrue'); }, true); document.body.addEventListener('click', function () { console.log('body captrue'); }, true); ev.addEventListener('click', function () { console.log('ev captrue'); }, true); // window -> document -> html -> body -> ev
自定義事件
let ev = document.getElementById('ev'); let eve1 = new Event('test1'); ev.addEventListener('test1', function () { console.log('test1 dispatch'); }); setTimeout(function () { ev.dispatchEvent(eve1); }, 1000); /*bubbles: 一個布爾值, 代表該事件是否會冒泡 cancelable: 一個布爾值, 代表該事件是否能夠被取消 detail: 當事件初始化時傳遞的數據*/ let eve2 = new CustomEvent('test2', {bubbles: false, cancelable: true, detail: {a: 'aaa'}}); ev.addEventListener('test2', function (e) { console.log(e); console.log('test2 dispatch'); }); setTimeout(function () { ev.dispatchEvent(eve2); }, 2000);
HTTP協議的主要特色?
簡單快速,靈活,無鏈接,無狀態
HTTP報文的組成部分?
請求報文:請求行,請求頭,空行,請求體
響應報文:響應行,響應頭,空行,響應體
HTTP方法?
GET 獲取資源
POST 傳輸資源
PUT 更新資源
DELETE 刪除資源
HEAD 得到報文首部
POST和GET的區別?
重要的五點:
(1)GET在瀏覽器回退時是無害的,而POST會再次提交請求
(2)GET請求會被瀏覽器主動緩存,而POST不會,除非手動設置
(3)GET請求參數會被完整保留在瀏覽器歷史記錄裏,而POST中的參數不會被保留
(4)GET請求在URL中傳送的參數是有長度限制的,而POST沒有限制
(5)GET參數經過URL傳遞,POST放在Request body中
其餘不一樣:
GET產生的URL地址能夠被收藏,而POST不能夠
GET請求只能進行URL編碼,而POST支持多種編碼方式
對參數的數據類型,GET只接受ASCll字符,而POST沒有限制
GET比POST更不安全,由於參數直接暴露在URL上,因此不能用來傳遞敏感信息
HTTP狀態碼?
1xx: 指示信息-表示請求已經接收,繼續處理
2xx: 成功-表示請求已被成功接收
3xx: 重定向-要完成請求必須進行更進一步的操做
4xx: 客戶端錯誤-請求有語法錯誤或請求沒法實現
5xx: 服務端錯誤-服務端未能實現合法的請求
常見的狀態碼:
200 OK:客戶端請求成功
206 Partial Content:客戶發送了一個帶有Range頭的GET請求,服務端完成了它
301 Moved Permanently:所請求的頁面已經轉移至新的URL
302 Found:所請求的頁面已經臨時轉移至新的url
304 Not Modified:客戶端有緩衝的文檔併發出了一個條件性的請求,服務端告訴客戶,原來緩衝的文檔還能夠繼續使用
400 Bad Request:客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthorized:請求未經受權,這個狀態碼必須和WWW-Authenticate報頭域一塊兒使用
403 Forbidden:對被請求頁面的訪問被禁止
404 Not Found:請求資源不存在
500 Internal Server Error:服務器發生不可預期的錯誤,原來緩衝的文檔還能夠繼續使用
503 Server Unavailable:請求未完成,服務器臨時過載或宕機,一段時間後可能恢復正常
什麼是持久鏈接?
HTTP協議採用「請求-應答」模式,當使用普通模式,即非 Keep-Alive模式時,每一個請求/應答客戶端和服務器都要新建一個鏈接,完成以後當即斷開鏈接(HTTP協議爲無鏈接的協議)。
當使用Keep-Alive模式(又稱持久鏈接,鏈接重用)時,Keep-Alive功能使客戶端到服務器端的鏈接持續有效,當出現對服務器的後續請求時,Keep-Alive功能避免了創建或者從新創建鏈接。
什麼是管線化?
在使用持久鏈接的狀況下,某個鏈接上消息的傳遞相似於:
請求1 -> 響應1 -> 請求2 -> 響應2 -> 請求3 -> 響應3
某個鏈接上的消息變成了相似這樣(管線化)
請求1 -> 請求2 -> 請求3 -> 響應1 -> 響應2 -> 響應3
管線化特色:
一、管線化機制經過持久鏈接完成,僅 HTTP/1.1 支持此技術
二、只有GET和HEAD請求能夠進行管線化,而POST則有所限制
三、初次建立鏈接時不該啓動管線機制,由於對方(服務器)不必定支持 HTTP/1.1 版本的協議
四、管線化不會影響響應到來的順序,如上面的例子所示,響應返回的順序並未改變
五、HTTP/1.1 要求服務器端支持管線化,但並未要求服務器端也對響應進行管線化處理,只是要求對於管線化的請求不失敗便可
六、因爲上面提到的服務器端問題,開啓管線化極可能並不會帶來大幅度的性能提高,並且不少服務器端和代理程序對管線化的支持並很差,
所以現代瀏覽器如Chrome和FireFox默認並未開啓管線化支持
建立對象有幾種方法?
// 第一種方式:字面量 let o1 = {name: 'o1'}; let o2 = new Object({name: 'o2'}); // 第二種方式:經過構造函數 let M = function (name) { this.name = name; }; let o3 = new M('o3'); // 第三種方式 let p = {name: 'p'}; // Object.create() 的參數就是所建立出來的對象的__proto__ let o4 = Object.create(p); console.log(o4.__proto__ === p); // true
instanceof的原理?
當使用instanceof判斷一個對象實例的構造函數時,只要是在實例的原型鏈上的構造函數,instanceof 都返回true
console.log(o3 instanceof M); // true console.log(o3 instanceof Object); // true console.log(o3.__proto__ === M.prototype); // true console.log(M.prototype.__proto__ === Object.prototype); // true console.log(o3.__proto__.constructor === M); // true console.log(o3.__proto__.constructor === Object); // false
new運算符原理?
let new1 = function (func) { // 一個新對象被建立,它繼承自 func.prototype let o = Object.create(func.prototype); // 構造函數foo被執行。執行的時候,相應的參數會被傳入,同時上下文(this)會被指定爲這個新實例 // new func 等同於 new func(),只能用在不傳遞任何參數的狀況 let k = func.call(o); if (typeof k === 'object') { // 若是構造函數返回了一個對象,那麼這個對象會取代整個new出來的結果 return k; } else { // 若是構造函數沒有返回對象,那麼 new 出來的結果就是以前 Object.create 建立的對象 return o; } }; let o5 = new1(M); console.log(o5 instanceof M, o5 instanceof Object); // true true console.log(o5.__proto__.constructor === M); // true console.log(o5.__proto__.constructor === Object); // false M.prototype.walk = function () { console.log('walk'); }; o5.walk(); // 'walk' o3.walk(); // 'walk'
聲明類的方式
/*ES5類的聲明*/ function Animal () { this.name = 'name'; } /*ES6中class的聲明*/ class Animal2 { constructor () { this.name = name; } } /*實例化*/ console.log(new Animal(), new Animal2()); // Animal {name: "name"} Animal2 {name: ""}
js實現繼承的幾種方式
1.藉助構造函數實現繼承
原理:利用call、apply,改變父類的this指向
缺點:沒法繼承父類prototype上的屬性
function Parent1 () { this.name = 'parent1'; } Parent1.prototype.say = function () { console.log('say'); }; function Child1 () { Parent1.call(this); // apply this.type = 'child1'; } console.log(new Child1()); // Child1 {name: "parent1", type: "child1"} console.log(new Child1().say()); // Uncaught TypeError: (intermediate value).say is not a function
2.藉助原型鏈實現繼承
原理:原型鏈的原理
缺點:實例化出來的每個對象,他們的屬性會相互影響。(原型鏈中的原型對象是公用的)
function Parent2 () { this.name = 'parent2'; this.arr = [1, 2, 3]; } function Child2 () { this.type = 'child2'; } Child2.prototype = new Parent2(); let s1 = new Child2(); let s2 = new Child2(); s1.arr.push(4); console.log(s1.arr); // [1, 2, 3, 4] console.log(s2.arr); // [1, 2, 3, 4] console.log(s1.__proto__ === Child2.prototype); // true console.log(s1.__proto__ === s2.__proto__); // true
3.組合方式
缺點:父類的構造函數執行了兩次。。。
function Parent3 () { this.name = 'parent3'; this.arr = [1, 2, 3]; } function Child3 () { Parent3.call(this); this.type = 'child3'; } Child3.prototype = new Parent3(); let s3 = new Child3(); let s4 = new Child3(); s3.arr.push(4); console.log(s3.arr, s4.arr); // [1, 2, 3, 4] [1, 2, 3]
4.組合方式的優化1
缺點:經過子類實例化的對象,它的constructor指向了父類而不是子類,沒法區分實例是由父類創造的仍是子類創造的
function Parent4 () { this.name = 'parent4'; this.arr = [1, 2, 3]; } function Child4 () { Parent4.call(this); this.type = 'child4'; } Child4.prototype = Parent4.prototype; let s5 = new Child4(); console.log(s5 instanceof Child4, s5 instanceof Parent4); // true true // s5是經過new Child4()建立的,它的constructor應該指向Child4,可是卻指向了Parent4 console.log(s5.constructor); // f Parent4 () {}
5.組合方式的優化2
js實現繼承比較完美的方案
function Parent5 () { this.name = 'parent5'; this.arr = [1, 2, 3]; } function Child5 () { Parent5.call(this); this.type = 'child5'; } // Object.create 建立了一箇中間對象 Child5.prototype = Object.create(Parent5.prototype); // 若是一下這句代碼放在上一種方案,由於Child4.prototype也是一個對象(引用類型數據),直接賦值也是改的Parent4 Child5.prototype.constructor = Child5; let s7 = new Child5(); let s8 = new Child5(); s7.arr.push(4); console.log(s7.arr, s8.arr); // [1, 2, 3, 4] [1, 2, 3] console.log(s7 instanceof Child5, s7 instanceof Parent5); // true true console.log(s7.constructor); // ƒ Child5 () {}
1.什麼是同源策略以及限制
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制
限制:(1)Cookie、LocalStorage和IndexDB沒法讀取(2)DOM 沒法得到(3)AJAX請求不能發送
2.先後端如何通訊
Ajax WebSocket CORS
3.如何建立Ajax
(1)XMLHttpRequest 對象的工做流程
(2)兼容性處理
(3)事件的觸發條件
(4)事件的觸發順序
util.json = function (options) { var opt = { url: '', type: 'get', data: {}, success: function () {}, error: function () {}, }; util.extend(opt, options); if (opt.url) { var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); var data = opt.data, url = opt.url, type = opt.type.toUpperCase(), dataArr = []; for (var k in data) { dataArr.push(k + '=' + data[k]); } if (type === 'GET') { url = url + '?' + dataArr.join('&'); xhr.open(type, url.replace(/\?$/g, ''), true); xhr.send(); } if (type === 'POST') { xhr.open(type, url, true); xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(dataArr.join('&')); } xhr.onload = function () { if (xhr.status === 200 || xhr.status === 304) { var res; if (opt.success && opt.success instanceof Function) { res = xhr.responseText; if (typeof res ==== 'string') { res = JSON.parse(res); opt.success.call(xhr, res); } } } else { if (opt.error && opt.error instanceof Function) { opt.error.call(xhr, res); } } }; } };
4.跨域通訊的幾種方式
(1)JSONP
util.jsonp = function (url, onsuccess, onerror, charset) { var callbackName = util.getName('tt_player'); window[callbackName] = function () { if (onsuccess && util.isFunction(onsuccess)) { onsuccess(arguments[0]); } }; var script = util.createScript(url + '&callback=' + callbackName, charset); script.onload = script.onreadystatechange = function () { if (!script.readyState || /loaded|complete/.test(script.readyState)) { script.onload = script.onreadystatechange = null; // 移除該script的 DOM 對象 if (script.parentNode) { script.parentNode.removeChild(script); } // 刪除函數或變量 window[callbackName] = null; } }; script.onerror = function () { if (onerror && util.isFunction(onerror)) { onerror(); } }; document.getElementsByTagName('head')[0].appendChild(script); };
舉個例子
// 使用jsonp的方式向頁面動態添加了script,發出一個請求。注意callback=須要執行的函數名 <script src="http://www.abc.com/?data=name&callback=jsonp" charset="utf-8"></script> // 上面的請求會返回以下內容,你在本地定義了全局函數jsonp(),隨之執行 <script type="text/javascript"> jsonp({ data: {}, // ... }); </script>
(2)Hash
// 利用hash,場景是當前頁面 A 經過iframe或frame嵌入了跨域的頁面 B // 在A中僞代碼以下: var B = document.getElementsByTagName('iframe'); B.src = B.src + '#' + 'data'; // 在B中的僞代碼以下 window.onhashchange = function () { var data = window.location.hash; };
(3)postMessage
HTML5的標準,利用一些API就能實現
// 窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息 // 在A中僞代碼以下: window.postMessage('data', 'http://B.com'); // 在B中的僞代碼以下:在窗口B中監聽 window.addEventListener('message', function (event) { console.log(event.origin); console.log(event.source); console.log(event.data); }, false);
(4)WebSocket
var ws = new WebSocket('wss://echo.websocket.org'); ws.onopen = function (evt) { console.log('Connection open ...'); ws.send('Hello WebSockets!'); }; ws.onmessage = function (evt) { console.log('Received Message: ', evt.data); ws.close(); }; ws.onclose = function (evt) { console.log('Connection closed.'); };
Websocket【參考資料】:http://www.ruanyifeng.com/blo...
(5)CORS
// url(必選),options(可選) fetch('/some/url/', { method: 'get', }).then(function (response) { }).catch(function (err) { // 出錯了,等價於 then 的第二個參數,但這樣更好用更直觀 });
CORS【參考資料】:http://www.ruanyifeng.com/blo...
1.CSRF
CSRF,一般稱爲跨站請求僞造,英文名 Cross-site request forgery
攻擊原理:
防護措施:
token驗證
referer驗證(頁面來源驗證)
隱藏令牌(相似token,把token放在http header中,不放在連接上)
2.XSS
XSS(cross-site scripting 跨域腳本攻擊)
攻擊原理
注入js腳本
防護措施
宗旨:讓注入的js腳本沒法執行
1.什麼是DOCTYPE及做用
DTD(document type definition, 文檔類型定義)是一系列的語法規則,用來定義XML或(X)HTML的文件類型。瀏覽器會使用它來判斷文檔類型,決定使用何種協議來解析,以及切換瀏覽器模式。(DTD就是告訴瀏覽器,我是什麼文檔類型,應該用什麼引擎來解析、渲染文檔)
DOCTYPE是用來聲明文檔類型和DTD規範的,一個主要的用途即是文件的合法性驗證。若是文件代碼不合法,那麼瀏覽器解析時便會出一些差錯。(DOCTYPE就是用來告訴瀏覽器,當前文檔是什麼文檔類型的)
常見的DOCTYPE有哪些?
HTML5 <!DOCTYPE html>
HTML 4.01 Strict 嚴格模式
HTML 4.01 Transitional 傳統模式
2.重排Reflow
定義:DOM結構中的各個元素都有本身的盒子,這些都須要瀏覽器根據各類樣式來計算並根據計算結果將元素放到它該出現的位置,這個過程稱爲reflow。
觸發Reflow的條件:
一、當你增長、刪除、修改DOM節點時,會致使Reflow或Repaint
二、當你移動DOM的位置,或是搞個動畫的時候
三、當你修改CSS樣式的時候
四、當你Resize窗口的時候(移動端沒有這個問題),或是滾動的時候
五、當你修改網頁的默認字體時
怎樣避免Reflow?(也就是避免觸發Reflow的條件)
3.重繪Repaint
定義:當各類盒子的位置、大小以及其餘屬性,例如顏色、字體大小等都肯定下來後,瀏覽器因而便把這些元素都按照各自的特性繪製了一遍,因而頁面的內容出現了,這個過程稱之爲repaint(頁面要呈現的內容通通畫在屏幕上)。
觸發Repaint的條件:(頁面顯示的內容不同了,就是重繪了)
DOM改動、CSS改動
怎樣減小Repaint?(頻繁操做DOM時,利用 document.createDocumentFragment() 建立臨時節點最後只操做一次DOM等等)
js是單線程的語言(同個時間只能作一件事)
js任務隊列:任務裏有同步任務和異步任務,先執行完同步任務,纔會執行異步任務
同步任務:
while,for,alert...
console.log('a'); while (true) { } console.log('b'); // 只打印了a,後續沒有執行,while是個同步任務
異步任務:
setTimeOut 和 setInterval (setTimeout 時間到了以後,纔會把函數體扔到異步隊列中,等待事件循環以後執行)
DOM事件、異步ajax、ES6中的Promise...
提高頁面性能的方法有哪些?
一、資源壓縮合並,減小HTTP請求
二、非核心代碼異步加載 -> 異步加載的方式 -> 異步加載的區別
三、利用瀏覽緩存 -> 緩存的分類 -> 緩存的原理
四、使用CDN加速資源(網絡優化)
五、預解析DNS
頁面中全部的a標籤,高級瀏覽器是默認打開a標籤DNS預解析的。但網站若是是https協議的,不少瀏覽器是默認關閉a標籤DNS預解析的。
<meta http-equiv="x-dns-prefetch-control" content="on"> 強制打開a標籤的DNS預解析,放到head中
<link rel="dns-prefetch" href="//host_name_to_prefetch.com"> DNS預解析,放到head中
異步加載
一、異步加載的方式
(1)動態腳本加載 (2)defer (3)async
二、異步加載的區別
(1)defer 是在HTML解析完以後纔會執行,若是是多個,按照加載的順序依次執行
(2)async 是在加載完以後當即執行,若是是多個,執行順序和加載順序無關
<!--defer 按照加載的順序依次執行--> <script src="defer1.js" defer></script> <script src="defer2.js" defer></script> <!--async 執行順序和加載順序無關,先解析完成的先執行--> <script src="async1.js" async></script> <script src="async2.js" async></script>
瀏覽器緩存
一、緩存的分類
(1)強緩存(本地已有資源文件,不詢問服務器,直接拿來用)
Expires Expires:Tue, 07 May 2019 22:08:48 GMT Cache-Control Cache-Control:max-age=3600
(2)協商緩存(本地已有資源文件,可是不肯定是否要用,要詢問服務器這個資源是否可用)
Last-Modified If-Modified-Since Last-Modified:Tue, 07 May 2019 22:08:48 GMT Etag If-None-Match
二、緩存原理:
資源文件在瀏覽器中存在的備份(副本)。頁面中有個圖片,請求回來以後緩存到本地(電腦磁盤),瀏覽器在下次請求這個圖片的時候,是從磁盤直接讀取這個圖片,而不會去請求圖片地址。
前端錯誤的分類
一、即時運行錯誤:代碼錯誤
二、資源加載錯誤
錯誤的捕獲方式
一、即時運行錯誤的捕獲方式
(1) try...catch
(2) window.onerror (沒法捕獲資源加載錯誤,好比script的資源加載錯誤,不會向上冒泡到window)
<script> window.addEventListener('error', function (e) { console.log('捕獲', e); }, true); </script> <script src="http://baidu.com/test.js"></script> <!--錯誤的資源-->
二、資源加載錯誤的捕獲方式
(1)object.onerror 事件,image對象、script標籤
(2)performance.getEntries() 獲取全部已加載資源的加載時長,能夠間接的拿到沒有加載的資源錯誤
(3)Error 事件捕獲(經過事件捕獲,而不是冒泡)
延伸:跨域的js運行錯誤能夠捕獲嗎,錯誤提示什麼,應該怎麼處理?
一、在 script 標籤增長 crossorigin 屬性(客戶端作)
二、設置 js 資源響應頭 Access-Control-Allow-Origin:* (服務端作)
上報錯誤的基本原理
一、採用Ajax通訊的方式上報
二、利用Image對象上報
(new Image()).src = 'http://www.baidu.com/testwqe?rw=erdf23';