前端基础之浏览器(一)

浏览器

1.1 cookie sessionStorage localStorage 区别

共同点:

都是保存在浏览器端、且同源的

区别:

  1. cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下

  2. 存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大

  3. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭

  4. 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的

  5. web Storage支持事件通知机制,可以将数据更新的通知发送给监听者

  6. Storage的api接口使用更方便

1.2 如何写一个会过期的localStorage,说说想法

惰性删除 和 定时删除

惰性删除

惰性删除是指,某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。

var lsc = (function (self) {
var prefix = 'lsc_'
    /**
    * 增加一个键值对数据
    * @param key 键
    * @param val 值
    * @param expires 过期时间,单位为秒
    */
    self.set = function(key, val, expires) {
        key = prefix + key;
        val = JSON.stringify({'val': val, 'expires': new Date().getTime() + expires * 1000});
        localStorage.setItem(key, val);
    };
    /**
    * 读取对应键的值数据
    * @param key 键
    * @returns {null|*} 对应键的值
    */
    self.get = function(key) {
        key = prefix + key;
        var val = localStorage.getItem(key);
        if (!val) {
            return null;
        }
        val = JSON.parse(val);
        if (val.expires < new Date().getTime()) {
            localStorage.removeItem(key);
            return null;
        }
        return val.val;
    };
    return self;
}(lsc || {}));

定时删除

定时删除是指,每隔一段时间执行一次删除操作

  1. 随机测试20个设置了过期时间的key。
  2. 删除所有发现的已过期的key。
  3. 若删除的key超过5个则重复步骤****1,直至重复500次。
var lsc = (function (self) {
    var prefix = 'lsc_'
    var list = [];
    //初始化
    self.init = function () {
        var keys = Object.keys(localStorage);
        var reg = new RegExp('^' + prefix);
        var temp = [];
        //遍历所有localStorage中的所有key
        for (var i = 0; i < keys.length; i++) {
            //找出可过期缓存的key
            if (reg.test(keys[i])) {
                temp.push(keys[i]);
            }
        }
        list = temp;
    };
    self.init();
    self.check = function () {
        if (!list || list.length == 0) {
            return;
        }
        var checkCount = 0;
    while (checkCount < 500) {
        var expireCount = 0;
        // 随机测试20个设置了过期时间的key
        for (var i = 0; i < 20; i++) {
            if (list.length == 0) {
                break;
            }
            var index = Math.floor(Math.random() * list.length);
            var key = list[index];
            var val = localStorage.getItem(list[index]);
            // 从list中删除被惰性删除的key
            if (!val) {
                list.splice(index, 1);
                expireCount++;
                continue;
            }
            val = JSON.parse(val);
            // 删除所有发现的已过期的key
            if (val.expires < new Date().getTime()) {
                list.splice(index, 1);
                localStorage.removeItem(key);
                expireCount++;
            }
        }
        // 若删除的key不超过5个则跳出循环
        if (expireCount <= 5 || list.length == 0) {
            break;
        }
        checkCount++;
        }
    }
    //每隔一秒执行一次定时删除
    window.setInterval(self.check, 1000);
    return self;
}(lsc || {}));

1.3 localStorage 能跨域吗

不能

解决办法

  • 通过postMessage来实现跨源通信
  • 可以实现一个公共的iframe部署在某个域名中,作为共享域
  • 将需要实现localStorage跨域通信的页面嵌入这个iframe

1.4 memory cache 如何开启

memory cache 如何开启是一种比较特殊的缓存,他不受max-age、no-cache等配置的影响,即使我们不设置缓存,如果当前的内存空间比较充裕的话,一些资源还是会被缓存下来。但这种缓存是暂时的,一旦关闭了浏览器,这一部分用于缓存的内存空间就会被释放掉。如果真的不想使用缓存,可以设置no-store,这样,即便是内存缓存,也不会生效

1.5 localstorage的注意哪些问题

  1. 兼容性问题
  2. localStorage在浏览器的隐私模式下面是不可读取的
  3. localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
  4. localStorage不能被爬虫抓取到

1.6 浏览器输入URL发生了什么

  1. URL 解析
  2. DNS 查询
  3. TCP 连接
  4. 处理请求
  5. 接受响应
  6. 渲染页面

1.7 浏览器是如何渲染页面的?

不同浏览器内核渲染机制有所区别

  1. HTML 被 HTML 解析器解析成 DOM 树;
  2. CSS 被 CSS 解析器解析成 CSSOM 树;
  3. 结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment;
  4. 生成布局(flow),浏览器在屏幕上“画”出渲染树中的所有节点;
  5. 将布局绘制(paint)在屏幕上,显示出整个页面。

webkit

Gecko

1.8 重绘、重排

概念

  1. 重排(Reflow):当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树
  2. 重绘(Repaint):是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。比如改变某个元素的背景色、文字颜色、边框颜色等等

区别:

重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置)

引发重排

  1. 添加、删除可见的dom
  2. 元素的位置改变
  3. 元素的尺寸改变(外边距、内边距、边框厚度、宽高、等几何属性)
  4. 页面渲染初始化
  5. 浏览器窗口尺寸改变
  6. 获取某些属性。当获取一些属性时,浏览器为取得正确的值也会触发重排,它会导致队列刷新,这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。所以,在多次使用这些值时应进行缓存

优化方案

浏览器会维护1个队列,把所有会引起重排,重绘的操作放入这个队列,等队列中的操作到一定数量或者到了一定时间间隔,浏览器就会flush队列,进行一批处理,这样多次重排,重绘变成一次重排重绘

减少 reflow/repaint:

  1. 不要一条一条地修改 DOM 的样式。可以先定义好 css 的 class,然后修改 DOM 的className。

  2. 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。

  3. 为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会reflow 的。

  4. 千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。(table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。)

  5. 不要在布局信息改变的时候做查询(会导致渲染队列强制刷新)

1.9 事件循环(Event loop)

主线程从"任务队列"中读取执行事件,这个过程是循环不断的,这个机制被称为事件循环

JavaScript 的事件分两种

  1. 宏任务:包括整体代码 script,setTimeout,setInterval
  2. 微任务:Promise.then(非 new Promise),process.nextTick(node 中)

具体执行:

事件的执行顺序——先执行宏任务,然后执行微任务,任务有同步的任务和异步的任务,同步的进入主线程,异步的进入 Event Table 并注册函数,异步事件完成后,会将回调函数放在队列中,如果还有异步的宏任务,那么就会进行循环执行上述的操作

主 线程会不断从任务队列中按顺序取任务执行,每执行完一个任务都会检查microtask队列是否为空(执行完一个 任务的具体标志是函数执行栈为空),如果不为空则会一次性执行完所有microtask。然后再进入下一个循环去 任务队列中取下一个任务执行

详细步骤

  1. 选择当前要执行的宏任务队列,选择一个最先进入任务队列的宏任务,如果没有宏任务可以选择,则会 跳转至microtask的执行步骤。

  2. 将事件循环的当前运行宏任务设置为已选择的宏任务。

  3. 运行宏任务。

  4. 将事件循环的当前运行任务设置为null。

  5. 将运行完的宏任务从宏任务队列中移除。

  6. microtasks步骤:进入microtask检查点。

  7. 更新界面渲染。

  8. 返回第一步。

执行进入microtask检查的的具体步骤如下:

  1. 设置进入microtask检查点的标志为true。
  2. 当事件循环的微任务队列不为空时:选择一个最先进入microtask队列的microtask;设置事

件循环的当 前运行任务为已选择的microtask;运行microtask;设置事件循环的当前运行任务

为null;将运行结束 的microtask从microtask队列中移除。

  1. 对于相应事件循环的每个环境设置对象(environment settings object),通知它们哪些

promise为 rejected。

  1. 清理indexedDB的事务。
  2. 设置进入microtask检查点的标志为false。

注意

当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行

1.10 let a = 1 挂载在哪里?

var a 挂载在window下。而let是挂载在 全局函数下面

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容