答:我平时喜欢研究一些网站,并对一些技术的原理和好玩的点感兴趣,我本身也喜欢思考,也喜欢尝试探索有没有更好的方式和实现。(有所收留,不要所有说出来,稍微留一点悬念留做面试官来提问)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]
主要考察点:乐观积极、主动沟通、逻辑顺畅、上进有责任心、有主张,作事果断、职业竞争力、职业规划
业务能力:能够作到行业第一
思考能力:对同一件事能够从不一样角度去思考,找到最优解
学习能力:不断学习新的业务,沉淀、总结
无上限的付出:对于没法解决的问题能够熬夜、加班
目标是什么:在业务上成为专家,在技术上成为行业大牛
近阶段的目标:不断的学习积累各方面地经验,以学习为主
长期目标:作几件有价值的事情,如开源做品、技术框架等
方式方法:先完成业务上的主要问题,作到极致,而后逐步向目标靠拢