【考前必看三】面试前夕知识点梳理之前端

三、前端

1. 前端性能优化策略

  • 减少 HTTP 请求
  • CSS 放在头部、避免使用 CSS 表达式
  • JS 放在尾部、精简 JS
  • 使用外部 CSS 和 JS 文件
  • 删除重复脚本、压缩组件
  • 避免重定向
  • 使用缓存
  • 使用 CDN、减少 CDN 查找

2. 跨域解决方案及其原理

同源策略/SOP(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个IP地址,也非同源。

常见的跨域场景(不允许通信):

(1)不同协议,同一域名:http://www.domain.com/a.js 和 https://www.domain.com/b.js

(2)同一域名,不同端口:http://www.domain.com:8000/a.js 和 http://www.domain.com/b.js

(3)不同域名:http://www.domain1.com/a.js 和 http://www.domain2.com/b.js

(4)主域相同,子域不同:http://www.domain.com/a.js 和 http://x.domain.com/b.js 和 http://domain.com/c.js

(5)域名和域名对应相同IP:http://www.domain.com/a.js 和 http://192.168.4.12/b.js

跨域解决方案:

(1)通过 jsonp 跨域

(2)document.domain + iframe 跨域:仅限主域相同,子域不同的跨域场景。

(3)location.hash + iframe 跨域:a欲与b跨域相互通信,通过中间页c来实现。

(4)window.name + iframe 跨域

(5)postMessage 跨域

(6)跨域资源共享(CORS):只需要服务端设置Access-Control-Allow-Origin即可。

(7)nginx 代理跨域

(8)nodejs 中间件代理跨域

(9)WebSocket 协议跨域

跨域解决方案的原理

3. 防抖和节流

防抖函数的作用

防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着 N 秒内函数只会被执行一次,如果 N 秒内再次被触发,则 重新 计算延迟时间。

防抖函数的实现

  • 事件第一次触发时,timeout 是 null,调用 later(),若 immediate 为true,那么立即调用 func.apply(this, params);如果 immediate 为 false,那么过 wait 之后,调用 func.apply(this, params)。
  • 事件第二次触发时,如果 timeout 已经重置为 null (即 setTimeout 的倒计时结束),那么流程与第一次触发时一样,若 timeout 不为 null (即 setTimeout 的倒计时未结束),那么清空定时器,重新开始计时。
function debounce(func, wait, immediate = true) {
    let timeout, result;
    // 延迟执行函数
    const later = (context, args) => setTimeout(() => {
        timeout = null;// 倒计时结束
        if (!immediate) {
            // 执行回调
            result = func.apply(context, args);
            context = args = null;
        }
    }, wait);
    let debounced = function (...params) {
        if (!timeout) {
            timeout = later(this, params);
            if (immediate) {
                // 立即执行
                result = func.apply(this, params);
            }
        } else {
            clearTimeout(timeout);
            // 函数在每个等待时延的结束被调用
            timeout = later(this, params);
        }
        return result;
    }
    // 提供在外部清空定时器的方法
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null;
    };
    return debounced;
};

immediate 为 true 时,表示函数在每个等待时延的开始被调用。immediate 为 false 时,表示函数在每个等待时延的结束被调用。 

防抖的应用场景

  1. 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。

  2. 表单验证。

  3. 按钮提交事件。

  4. 浏览器窗口缩放,resize 事件 (如窗口停止改变大小之后重新计算布局) 等。

节流函数的作用

节流函数的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。

节流函数的实现

function throttle(func, wait, options = {}) {
    var timeout, context, args, result;
    var previous = 0;
    var later = function () {
        previous = options.leading === false ? 0 : (Date.now() || new Date().getTime());
        timeout = null;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
    };
 
    var throttled = function () {
        var now = Date.now() || new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        //remaining 为距离下次执行 func 的时间
        //remaining > wait,表示客户端系统时间被调整过
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        //remaining 小于等于 0,表示事件触发的间隔时间大于设置的 wait
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                // 清空定时器
                clearTimeout(timeout);
                timeout = null;
            }
            // 重置 previous
            previous = now;
            // 执行函数
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
        return result;
    };
 
    throttled.cancel = function () {
        clearTimeout(timeout);
        previous = 0;
        timeout = context = args = null;
    };
 
    return throttled;
}

禁用第一次首先执行,传递 {leading: false} ;想禁用最后一次执行,传递 {trailing: false}。

节流的应用场景

  1. 按钮点击事件。

  2. 拖拽事件。

  3. onScoll。

  4. 计算鼠标移动的距离 (mousemove)。

4. link 和 import 的区别

link 属于 XHTML 标签,而 @import 是 CSS 提供的。

(1)引用的方式不同:

link(外部引用): <link rel="stylesheet" href="xxx.css"  type="text/css" />
 
@import(导入式): @import url(xxx.css);

(2)放置的位置不同:link 一般放在 head 标签中,而 @import 必须放在 <style  type="text/css"> 标签中。

(3)加载方式不同:link 会和 dom 结构一同加载渲染,而 @import 只能等 dom 结构加载完成以后才能加载渲染页面。

(4)兼容性不同:@import 只能在 IE6 以上才能识别,而 link 是 XHTML 标签,无兼容问题。

(5)样式权重不同:link 方式的样式的权重高于 @import。

(6)改变样式:link 支持使用 JavaScript 改变样式,而 @import 不可以。

(7)加载内容不同:link 除了可以加载 css 文件以外,还可以加载 MIME 类型的文件;而 @import 只能加载 css 文件。

5. 浏览器内核

  • IE、傲游、Avant、腾讯TT (trident内核)
  • Mozilla Firefox (gecko内核)
  • Safari (webkit内核)
  • Chrome (Blink内核)
  • Opera (原为Presto内核,现为Blink内核)

6. 浏览器兼容问题及其解决方案

问题一:在不加样式控制的情况下,标签默认的外补丁(margin)和内补丁(padding)不同

解决方案: CSS设置 *{ margin:0; padding:0; }

问题二:块级属性标签 float 之后,如果有左右 margin,那么在 IE6 中显示的 margin 比设置的大

解决方案: 在float的标签样式中加入 { display: inline; }, 将其转化为行内属性

问题三:行内属性标签,在设置 display:block 之后,如果采用 float 布局,同时又有左右 margin 的情况下,那么在 IE6 中显示的间距有 bug

解决方案: 在 { display:block; } 后面加入 { display:inline; display:table; }

问题四:如果给标签设置较小的高度(一般小于10px),那么在IE6,IE7和遨游中这个标签的高度会超出你设置的高度

在IE6、IE7和遨游中,这个标签的高度不受你设置的高度的控制,它会达到默认的行高。这是因为 IE8 之前的浏览器都会给标签一个最小默认的行高的高度,即使标签是空的,这个标签的高度还是会达到默认的行高。

解决方案: 给超出高度的标签设置 { overflow:hidden; } 或者设置行高 { line-height } 小于你设置的高度

问题五:如果给标签设置最低高度 min-height,会出现不兼容的情况

解决方案: 如果我们要设置一个标签的最小高度是200px,需要进行的设置为:
{
    min-height:200px; 
    height:auto !important; 
    height:200px; 
    overflow:visible;
}

问题六:图片之间默认有间距

几个 img 标签放在一起的时候,有些浏览器会有默认的间距,加了问题一中提到的通配符也不起作用。

解决方案: 将 img 设置为 float 属性

问题七:格式为PNG24的图片在IE6浏览器上会出现背景

解决方案:把图片改成 PNG8 格式

问题八:设置透明度(兼容所有浏览器)

.tran_class {   
    filter: alpha(opacity=50); // IE浏览器 (trident内核)
    -moz-opacity: 0.5;  // 老版Mozilla firefox (gecko内核) 
    -khtml-opacity: 0.5;   // 老版Safari (webkit内核)
    opacity: 0.5;   // 支持opacity的所有浏览器,如:Chrome (Blink内核)、opera (以前是presto内核,现在改用google chrome的Blink内核)
}

问题九: IE6,IE7中 ol 的序号全为1,不递增

解决方案: li设置样式 { display: list-item }

问题十: IE6,IE7不支持 display:inline-block

解决方案: 设置 inline, 并触发 haslayout
{ display:inline-block; *display:inline; *zoom:1 }

问题十一: 使用 hack 解决浏览器兼容问题

不同的浏览器对CSS的解析不同,会导致生成的页面效果不同。通过使用 hack 可以解决浏览器兼容问题(针对的更多是 老式/旧版本 浏览器),但不推荐使用,因为当代码量多时,编写复杂度会变高,还可能会在浏览器更新之后产生更多的兼容问题。

hack 可以理解为不同浏览器识别的标识符。

(1)五大浏览器的hack

div {
    transform: rotate(90deg);         /* 标准模式 */
    -moz-transform: rotate(90deg);    /* Firefox */
    -webkit-transform: rotate(90deg); /* Safari and Chrome */
    -o-transform: rotate(90deg);      /* Opera */
    -ms-transform: rotate(90deg);     /* IE */
}

(2)CSS属性hack

IE6能识别 下划线_ 和 星号* ,但不能识别 !important
IE7能识别 星号* 和 !important ,但不识别 下划线_
Firefox 能识别 !important ,但不识别 下划线_ 和 星号*
书写顺序:FF IE7 IE6
 
比如这样一个CSS设置:
{ 
    height:300px; 
    *height:200px; 
    _height:100px; 
}
 
在IE6中从上往下读,直到_height,把高度设置成了100px;
在IE7中从上往下读,直到*height,把高度设置成了200px;
在其他浏览器中,把高度设置成了300px。

(3)CSS选择符hack

IE6能识别*html .class{}
IE7能识别*+html .class{} 或者 *:first-child+html .class{}

(4)条件注释法:这种方式是 IE 浏览器专有的 hack 方式,微软官方推荐使用。 

问题十二:获取自定义属性

IE浏览器下,可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute()获取自定义属性。

Firefox浏览器下,只能使用getAttribute()获取自定义属性。

解决方案:统一使用 getAttribute() 获取自定义属性

问题十三:Chrome 浏览器的中文界面下默认会将小于 12px 的文本强制按照 12px 显示

解决方案:加入 CSS 属性 {-webkit-text-size-adjust: none; }

问题十四:超链接访问过后 hover 样式就不出现了;被点击访问过的超链接样式不再具有 hover 和 active 了

解决方案:改变 CSS 属性的排列顺序:
L-V-H-A :  a:link {} a:visited {} a:hover {} a:active {} 

问题十五:even对象

IE浏览器下,even对象有x,y属性,但是没有pageX,pageY属性。

Firefox浏览器下,event对象有pageX,pageY属性,但是没有x,y属性。

解决方案:条件注释
缺点:在IE浏览器下可能会增加额外的 HTTP 请求。

7. 从输入网址到最后浏览器呈现页面内容,中间发生了什么?

(1)输入网址,浏览器,发送UDP包给DNS服务器,通过DNS解析得到网址的IP地址(即服务器的IP),并将IP地址缓存。

(2)客户端(浏览器)和服务器端之间建立TCP连接:由于TCP邮差需要知道4个东西(本机IP,本机端口,服务器IP,服务器端口),现在只知道了本机IP,服务器IP, 两个端口怎么办?其中,本机端口很简单,操作系统可以给浏览器随机分配一个, 服务器端口更简单,用的是一个“众所周知”的端口,HTTP服务就是80(HTTPS服务就是443), 我们直接告诉TCP邮差就行。经过三次握手以后,客户端和服务器端的TCP连接就建立起来了! 

(3)浏览器发送HTTP请求。

(4)Web服务器处理请求,并将HTTP Response(一个HTML页面)返回给浏览器。

(5)浏览器再次发起请求:由于这个HTML页面中可能引用了大量其他资源,例如JS文件,CSS文件,图片等,这些资源也位于服务器端,并且可能位于另外一个域名下面。所以浏览器只好一个个地下载,从使用DNS获取IP开始,之前做过的事情还要再来一遍。

(6)当服务器把JS,CSS这些文件发送给浏览器时,会告诉浏览器这些文件什么时候过期(使用Cache-Control或者Expire),浏览器可以把文件缓存到本地,当第二次请求同样的文件时,如果不过期,直接从本地取就可以了。如果过期了,浏览器就可以询问服务器端,文件有没有修改过?(依据是上一次服务器发送的Last-Modified和ETag),如果没有修改过(304 Not Modified),还可以使用缓存。否则的话服务器就会把最新的文件发回到浏览器。

(7)现在浏览器拥有了 HTML、CSS 和 JavaScript(可以修改 DOM Tree),开始进行渲染

  • HTML,浏览器把它解析成 DOM Tree;CSS,浏览器把它解析成 CSS Rule Tree
  • DOM Tree 和 CSS Rule Tree 解析完成之后,被附加到一起,形成渲染树 Render Tree
  • (重排 - Reflow) 计算节点信息:根据渲染树计算每个节点的几何信息
  • (重绘 - Repaint) 渲染绘制:根据计算好的节点信息,渲染绘制整个页面

最后,我们就能看到呈现的页面了。

8. 重排和重绘

重排:若渲染树的部分节点更新,且尺寸变化,就会发生重排。

重绘:若渲染树的部分节点更新,但不改变其他节点,就会发生重绘。

PS:重绘不一定导致重排,但重排一定会导致重绘。重排会产生比重绘更大的开销。

触发重排:

  • (1)页面第一次渲染:在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排
  • (2)浏览器窗口尺寸改变
  • (3)元素位置和尺寸(宽、高、内外边距、边框等)发生改变的时候
  • (4)增加或删除DOM节点
  • (5)内容发生改变(文字数量或图片大小等等)
  • (6)元素字体大小变化
  • (7)激活CSS伪类(例如::hover) 
  • (8)增加或修改样式,设置style属性
  • (9)查询某些属性或调用某些方法,如:调用getComputedStyle方法,或者IE里的currentStyle时,也会触发重排
  • (10)display:none —— 设置该属性的元素将会消失,不占据空间

触发重绘:

  • (1)visibility:hidden —— visibility 属性规定元素是否可见。即使不可见的元素也会占据页面上的空间。
  • (2)outline —— outline (轮廓)是绘制于元素周围的一条线,位于边框边缘的外围。轮廓线不会占据空间,也不一定是矩形。
  • (3)背景颜色:color、background-color

如何减少重排和重绘以提升页面性能:

  • (1)样式集中改变。
  • (2)DOM离线化。
  • (3)批量添加DOM。
  • (4)复制节点,在副本中修改,然后直接替换当前的节点。
  • (5)降低受影响的节点:在页面顶部插入节点将影响后续所有节点,而绝对定位元素的改变会影响较少的元素,将position属性设置为absolute或fixed
  • (6)分离读写操作。
  • (7)缓存布局信息。
  • (8)使用 css spirit,也叫 css 精灵,它将所有的图片放到一张图片上,然后通过定位来实现图片的使用。

参考:https://www.imooc.com/article/45936

END

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章