浏览器相关知识

浏览器体系

一、 认识在浏览器运行态下的JS

  • 包含:BOM、DOM、ECMAScript
    (function(context, undefined){
        const _class = ['js', 'browser', 'vue']

        // 向全局中挂载
        window.classArr = _class.map(item => item)

        // 获取当前页面地址
        const _url = location.href

        // 设置tab标题
        document.title = 'zhaowa class'

        // 获取渲染节点
        document.getElementById('app')
    })(this)

追问:了解浏览器JS的执行态

简述: ECMAScript - 基础逻辑、数据处理

​ DOM - 对于浏览器视窗内,文本的相应操作

​ BOM - 对于浏览器本身区域能力的处理

二、BOM

1. location

属性说明
location.href“https://www.zhaowa.com/search?class=browser#comments”路径栏所有,当前加载页面完整的URL
location.origin“https://www.zhaowa.com”URL的原地址,只读
location.protocol“https:”页面使用的协议
location.host“www.zhaowa.com”服务器名及端口号
location.port“端口号” || " "请求的端口,如果URL中没有端口,则返回空字符串
location.pathname“/search/”URL中的路径和(或)文件名
location.search“?class=browser&id=2”URL的查询字符串.这个字符串以问号开头
location.hash“#comments” || " "URL散列值(#号后跟零或多个字符),如果没有则为空字符串
	location.assign('') // 跳转到指定path => 替换pathname
	location.replace('') // 同上,同时替换浏览历史
	location.reload()
	location.toString() // 产出当前地址字符串
location面试方向
  1. location本身api操作

    • 提取相关信息

    • api间对比 => assign vs replace

      使用window.location.assign("url")只会导致加载新文档。

      使用window.location.replace("url")将替换当前文档并用该 URL 替换当前历史记录,这样就无法返回上一个加载的文档。

  2. 路由相关: 跳转、参数、操作 => 场景:可返回(history)、是否刷新(hash)=> replace替换assign、携带参数

    • hash:根据#以及后面的字符对页面进行定位,使对应的id元素在可视区域显示,hash改变浏览器不会向服务器发送请求
    • history:可以在url里放传参,会使浏览器向服务器发送请求
  3. url处理 - 正则 or 手写js处理

  4. URI(统一资源标志符,uniform resource identifier) & URL(统一资源定位符,uniform resource locator)’

    • URI:资源标识符,当前页面的resource的id,相当于一个人的身份证,通过身份证号可以对应唯一一个资源
    • URL:资源定位符,当前页面存放的路径,当前定位的地址信息,相当于通过资源的地址来对应唯一一个资源

2. history

history.state => 存储当前页面的状态

history.pushState()

history.replaceState()

history面试方向
  1. 路由方向 history和hash的模式

    hash优缺点
    优点:
    a. 不需要后端配合,只需要前端配置路由表
    b. 兼容性好
    c. hash值改变不会发送请求
    缺点:hash需要加#,不符合url规范,不美观

    history优缺点:
    优点:符合url规范,美观
    缺点:
    a. 在输入地址或刷新页面时会重新请求,后端需要配置index.html页面用户匹配不到静态资源的情况,否则会出现404
    b. 兼容性差,利用了pushState和replaceState

    不同点:

    • hash有#,监听浏览器地址hash值变化,执行相应的js切换网页;

    • history 无#,利用history API实现url地址改变,网页内容改变;

    • 它们的区别最明显的就是hash会在浏览器地址后面增加#号,而history可以自定义地址

    • 回车刷新: hash 可以加载到hash值对应页面 ; history需要设置默认页面否则会404

    • 支持版本: hash支持低版本浏览器和IE浏览器 ; historyHTML5新推出的API

3. navigator

  • 浏览器系统信息大集合
    navigator.userAgent // 获取当前用户的环境信息
  • 面试方向
  1. userAgent 读取信息 => 浏览器兼容性、上报信息
    • 能够识别用户使用的操作系统及版本,CPU类型,浏览器及版本,浏览器渲染引擎,浏览器语言,浏览器插件等
  2. 剪切板、键盘

4. screen

表征显示区域 - 荧幕

面试方向 - 判断区域大小

  1. window 视窗判断:
    全局入口处:
    window.innerHeight
    window.innerWidth
    文本处获取:
    document.documentElement.clientHeight
    document.documentElement.clientWidth
    document.body.clientHeight
    document.body.clientWidth

  2. 网页视图的size -> offsetHeight = clientHeight + 滚动条 + 边框
    document.documentElement.offsetHeight
    document.documentElement.offsetWidth
    document.body.offsetHeight
    document.body.offsetWidth

  3. 动态定位:
    scrollLeft / scrollTop - 距离常规左 / 上滚动距离
    offsetLeft / offsetTop - 距离常规左 / 上距离

  4. 返回元素的大小及其相对于视口的位置

    ​ element.getBoundingClientRect()

    ​ element.getBoundingClientRect().top

    ​ element.getBoundingClientRect().left

    ​ element.getBoundingClientRect().bottom

    ​ element.getBoundingClientRect().right

  • 兼容性 - IE是会多出来2像素

三、 Event事件模型

	<div id="app">
    	<p id="dom"></p>
	</div>

冒泡 - ms: p => div => body => HTML => document

捕获 - ns: document => HTML => body => div => p

1. addEventListener

el.addEventListener(event, function, useCapture[是否捕获,默认值false])

2. 相关问题

1. 如何阻止事件的传播?
  1. event.stopPropgation() => 既能阻止冒泡,也能阻止捕获

    注意:阻止任何传递行为但无法阻止默认事件

  2. event.preventDefault() => 阻止默认事件,例如a标签跳转等等自带的事件能力

  3. event.stopImmediatePropagation() => 相同节点绑定多个同类事件,如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了event.stopImmediatePropagation()方法,则当前元素剩下的监听函数将不会被执行

2. 引申型面试核心: 兼容性 & 性能
  • attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段 addEventListener——兼容:firefox、chrome、IE、safari、opera

    • 区别:
      a. 传参:attachEvent 对于事件名需要加上’on’
      b. 执行顺序:attachEvent - 后绑定先执行; addEventListener - 先绑定先执行
      c. 解绑:detachEvent VS removeEventListener
      d. 阻断:event.cancelBubble = true VS event.stopPropgation()
      e. 默认事件拦截:event.returnValue = false VS event.preventDefault()
  • 手写兼容性事件绑定

    class bindEvent {
        constructor(element) {
            this.element = element;
        }
        // 绑定
        addEventListener = (type, handler) => {
            if(this.element.addEventListener) {
                this.element.addEventListener(type, handler, false)
            } else if(this.element.attachEvent) {
                this.element.attachEvent('on' + type, () => {
                    handler.call(element);
                })
            } else {
                this.element['on' + type] = handler;
            }
        }
        // 解绑
        removeEventListener = (type, handler) => {
            if(this.element.removeEventListener) {
                this.element.removeEventListener(type, handler, false)
            } else if(this.element.detachEvent) {
                this.element.detachEvent('on' + type, () => {
                    handler.call(element);
                })
            } else {
                this.element['on' + type] = null;
            }
        }
        // 全局的用static 阻断
        static stopPropgation(e) {
            if (e.stopPropagation) {
                e.stopPropagation()
            } else {
                e.cancelBubble = true;
            }
        }
        // 默认拦截
        static preventDefault(e) {
            if(e.preventDefault) {
                e.preventDefault()
            } else {
                e.returnValue = false;
            }
        }
    }
    
3. 性能优化 - 事件代理
<ul class="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul> 
<div class="content"></div>
    
var list = document.querySelector('list');
var li = list.getElementsByTagName('li');

// 代理前 - 硬碰硬
for(var n = 0; n < li.length; n++) {
    li[n].addEventListener('click', function() {
        // 业务逻辑
    })
}

// 代理后 - 利用事件传递
function onClick(e) {
    var e = e || window.event;

    if(e.target.nodeName.toLowCase() === 'li') {
        // 业务逻辑
        var liList = this.querySelectorAll('li');
        // ……
    }
}

list.addEventListener('click', onClick, false)

四、网络层

1. Ajax原理

	// 实例化
    const xhr = new XMLHttpRequest();

    //初始化建立
    xhr.open(method, url, async) // get/post; 请求的地址; 是否为异步请求

    // 方法的发送请求 - send
    xhr.send(data) // get - 可以不传或传入null,post - encodeURIComponent编码拼接

    // 接收
    // xhr.readyStatus - 0 - 尚未建立open;1 - 已经调用open; 2 - 已经调用send; 3 - 已经收到请求返回; 4- 请求已经完成
    xhr.onreadystatuschange = () => {
        if(xhr.readyStatus === 4) {
            // 判断http状态码
            if(xhr.status >= 200 &&
                xhr.status < 300 ||
                xhr.status == 304) {
                    // xhr.responseText
            }
        }
    }

    // 超时时间
    xhr.timeout = 30000
    xhr.ontimeout = () => {
        // 超时后
    }

2. 面试方向

  1. TCP => HTTP/HTTPs
  2. 状态码 => 2xx 4xx 5xx | 3xx => 浏览器缓存 => 强缓存(Expires + cache-control) / 协商缓存(last-modified + Etag)

3. 封装ajax手写

ajax({
    url: 'reqUrl',
    method: 'get',
    async: true,
    timeout: 30000,
    data: {
        payload: 'text'
    }
}).then(
    res => {}
    err => {}
).catch(err => {})

// 实现:
function ajax(options) {
    const {
        url,
        method,
        async,
        data,
        timeout
    } = options;

    const xhr = new XMLHttpRequest()

    //  配置超时事件
    if (timeout) {
        xhr.timeout = timeout;
    }

    return new Promise((resolve, reject) => {
        // 成功
        xhr.onreadystatuschange = () => {
            if(xhr.readyStatus === 4) {
                // 判断http状态码
                if(xhr.status >= 200 &&
                    xhr.status < 300 ||
                    xhr.status == 304) {
                        // 返回拦截器
                        resolve(xhr.responseText)
                } else {
                    //后端返回错误数据
                    reject()
                }
            }
        }

        // 失败
        xhr.onerror = err => reject(err)
        xhr.ontimeout = () => reject('timeout')

        // 传参处理
        let _params = []
        let encodeData = ''
        if (data instanceof Object) {
            for(let key in data) {
                // 参数编码
                _params.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
            }
            encodeData = _params.join('&')
        }

        // method判断连接
        if (method === 'get') {
            const index = url.indexOf('?')
			//没有'?'
            if(index === -1) {
                url += '?'
            } else if(index !== url.length -1) {
                url += '&'
            }

            url += encodeData
        }

        // 建立连接
        xhr.open(method, url, async)
        // 请求拦截器……
        // 发送请求
        if (method === 'get') {
            xhr.send(null)
        } else {
            // post
            xhr.setRequestHeader(
                //传参方法
                'content-type': 'application/x-www-form-urlencoded'
            )
            xhr.send(encodeData)
        }
    })
}
// 面试点: content-type => 内容类型 => 浏览器 => ff chrome

五、浏览器原理

面试题: 从url输入到页面展示发生了什么?

  • 获取到资源 => 渲染出页面

  • DOM - 生成文本树

  • CSSOM - CSS解析成树形数据结构

  • Render Tree: DOM + CSSOM生成树

  • Layout module:计算Render Tree每个节点具体的状态和位置

  • Painting:呈现到屏幕上

流程总结:Url => HTML解析 - JS + DOM + CSSOM => render tree / JS + css执行 => layout => painting

  • DOM和CSSOM生成的纵向切分

    bytes字节串 48 65 2C……) => <characters结构化语言 > => Tokens(tag tree) => Nodes(html|head|body) => DOM | CSSOM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巨龙王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值