关于浏览器的那些事情1

1 事件机制

document 往事件触发处传播,遇到注册的捕获事件会触发 传播到事件触发处时触发注册的事件
从事件触发处往 document 传播,遇到注册的冒泡事件会触发,事件触发⼀般来说会按照上⾯的顺序进⾏,但是也有特例,如果给⼀个⽬标节 点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执⾏

// 以下会先打印冒泡然后是捕获
node.addEventListener('click',(event) =>{
console.log('冒泡') },false);
node.addEventListener('click',(event) =>{
console.log('捕获 ') },true)

注册事件

通常我们使⽤ addEventListener 注册事件,该函数的第三个参数可以是布尔值,也可 以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 false 。
useCapture 决定了注册的事件是捕获事件还是冒泡事件
⼀般来说,我们只希望事件只触发在⽬标上,这时候可以使⽤ stopPropagation 来阻⽌
事件的进⼀步传播。通常我们认为 stopPropagation 是⽤来阻⽌事件冒泡的,其实该函 数也可以阻⽌捕获事件。 stopImmediatePropagation 同样也能实现阻⽌事件,但是还 能阻⽌该事件⽬标执⾏别的注册事件

node.addEventListener('click',(event) =>{
event.stopImmediatePropagation()
console.log('冒泡') },false);
// 点击 node 只会执⾏上⾯的函数,该函数不会执⾏
node.addEventListener('click',(event) => {
console.log('捕获 ') },true)

事件代理
如果⼀个节点中的⼦节点是动态⽣成的,那么⼦节点需要注册事件的话应该注 册在⽗节点上

<ul id="ul"> <li>1</li><li>2</li> <li>3</li> <li>4</li> <li>5</li>
</ul> <script>
let ul = document.querySelector('##ul')
ul.addEventListener('click', (event) => {
console.log(event.target); })
</script>

事件代理的⽅式相对于直接给⽬标注册事件来说,有以下优点
节省内存
不需要给⼦节点注销事件

2 跨域

因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端⼝ 有⼀个不同就是跨域, Ajax 请求会失败
JSONP
JSONP 的原理很简单,就是利⽤

<script src="http://domain/api?param1=a&param2=b&callback=jsonp"></script> <script>function jsonp(data) {console.log(data) }
</script>

JSONP 使⽤简单且兼容性不错,但是只限于 get 请求
CORS
CORS 需要浏览器和后端同时⽀持 浏览器会⾃动进⾏ CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了
CORS ,就实现了跨域。 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS 。 该属性表示哪些域名 可以访问资源,如果设置通配符则表示所有⽹站都可以访问资源 document.domain 该⽅式只能⽤于⼆级域名相同的情况下,⽐如 a.test.com 和 b.test.com 适⽤于该⽅式。
只需要给⻚⾯添加 document.domain = ‘test.com’ 表示⼆级域名都相同就可以实现跨域
postMessage
这种⽅式通常⽤于获取嵌⼊⻚⾯中的第三⽅⻚⾯数据。⼀个⻚⾯发送消息,另
⼀个⻚⾯判断来源并接收消息

// 发送消息端
window.parent.postMessage('message', 'http://blog.poetries.com');
// 接收消息端
var mc = new MessageChannel();
mc.addEventListener('message', (event) => {
var origin = event.origin || event.originalEvent.origin;
if (origin === 'http://blog.poetries.com') {
console.log('验证通过')
} });

3 Event loop

JS中的event loop

众所周知 JS 是⻔⾮阻塞单线程语⾔,因为在最初 JS 就是为了和浏览器交 互⽽诞⽣的。
如果 JS 是⻔多线程的语⾔话,我们在多个线程中处理 DOM
就可能会发⽣问题(⼀个线程中新加节点,另⼀个线程中删除节点)

JS 在执⾏的过程中会产⽣执⾏环境,这些执⾏环境会被顺序的加⼊到执⾏栈中。如果遇 到异步的代码,会被挂起并加⼊到 Task (有多种 task ) 队列中。⼀旦执⾏栈为空,
Event Loop 就会从 Task 队列中拿出需要执⾏的代码并放⼊执⾏栈中执⾏,所以本 质上来说 JS 中的异步还是同步⾏为

console.log('script start');
setTimeout(function() {
console.log('setTimeout'); }, 0);
console.log('script end');

不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务 ( microtask ) 和 宏任务( macrotask )。在 ES6 规范中,
microtask 称为 jobs,macrotask 称为 task

console.log('script start');
setTimeout(function() {console.log('setTimeout'); }, 0);
new Promise((resolve) => {console.log('Promise')resolve() }).then(function() {console.log('promise1'); }).then(function() {console.log('promise2'); });
console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTime

以上代码虽然 setTimeout写在Promise 之前,但是因为 Promise 属于微任务⽽ setTimeout 属于宏任务
微任务

process.nextTick
promise
Object.observe
MutationObserver

宏任务

script
setTimeout
setInterval
setImmediate
I/O
UI rendering
宏任务中包括了 script ,浏览器会先执⾏⼀个宏任务,接下来有异步代码 的话就先执⾏微任务

so 。。正确的⼀次 Event loop 顺序是这样的

执⾏同步代码,这属于宏任务
执⾏栈为空,查询是否有微任务需要执⾏
执⾏所有微任务必要的话渲染 UI 然后开始下⼀轮 Event loop ,执⾏宏任务中的异步代码

通过上述的 Event loop 顺序可知,如果宏任务中的异步代码有⼤量的计算 并且需要操作 DOM 的话,为了更快的响应界⾯响应,我们可以把操作 DOM
放⼊微任务中
Node 中的 Event loop

Node 中的 Event loop 和浏览器中的不相同。
Node 的 Event loop 分为 6 个阶段,它们会按照顺序反复运⾏

┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<──connections─── │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
timer
timers 阶段会执⾏ setTimeout 和 setInterval
⼀个 timer 指定的时间并不是准确时间,⽽是在达到这个时间后尽快执⾏回调,可能会因 为系统正在执⾏别的事务⽽延迟
I/O
I/O 阶段会执⾏除了 close 事件,定时器和 setImmediate 的回调
poll
poll 阶段很重要,这⼀阶段中,系统会做两件事情
执⾏到点的定时器
执⾏ poll 队列中的事件
并且当 poll 中没有定时器的情况下,会发现以下两件事情 如果 poll 队列不为空,会遍历回调队列并同步执⾏,直到队列为空或者系统限制 如果 poll 队列为空,会有两件事发⽣ 如果有 setImmediate 需要执⾏, poll 阶段会停⽌并且进⼊到 check 阶段执⾏setImmediate
如果没有 setImmediate 需要执⾏,会等待回调被加⼊到队列中并⽴即执⾏回调 如果有别的定时器需要被执⾏,会回到 timer 阶段执⾏回调。
check
check 阶段执⾏ setImmediate
close callbacks
close callbacks 阶段执⾏ close 事件
并且在 Node 中,有些情况下的定时器执⾏顺序是随机的

setTimeout(() => {console.log('setTimeout'); }, 0);
setImmediate(() => {console.log('setImmediate'); }// 这⾥可能会输出 setTimeout,setImmediate
// 可能也会相反的输出,这取决于性能
// 因为可能进⼊ event loop ⽤了不到 1 毫秒,这时候会执⾏ setImmediate
// 否则会执⾏ setTimeout

上⾯介绍的都是 macrotask 的执⾏情况, microtask 会在以上每个阶段完 成后⽴即执⾏

setTimeout(()=>{console.log('timer1')Promise.resolve().then(function() {console.log('promise1')}) }, 0)
setTimeout(()=>{console.log('timer2')Promise.resolve().then(function() {console.log('promise2')}) }, 0)// 以上代码在浏览器和 node 中打印情况是不同的
// 浏览器中⼀定打印 timer1, promise1, timer2, promise2
// node 中可能打印 timer1, timer2, promise1, promise2
// 也可能打印 timer1, promise1, timer2, promise2

Node 中的 process.nextTick 会先于其他 microtask 执⾏

setTimeout(() => {console.log("timer1");Promise.resolve().then(function() {console.log("promise1"); }); }, 0);
process.nextTick(() => {console.log("nextTick");});
// nextTick, timer1, promise1

4 Service Worker

Service workers 本质上充当Web应⽤程序与浏览器之间的代理服务器,
也 可以在⽹络可⽤时作为浏览器和⽹络间的代理。
它们旨在(除其他之外)使得 能够创建有效的离线体验,
拦截⽹络请求并基于⽹络是否可⽤以及更新的资源 是否驻留在服务器上来采取适当的动作
。他们还允许访问推送通知和后台同步 API

⽬前该技术通常⽤来做缓存⽂件,提⾼⾸屏速度

// index.js
if (navigator.serviceWorker) {
navigator.serviceWorker
.register("sw.js")
.then(function(registration) {
console.log("service worker 注册成功");
})
.catch(function(err) {
console.log("servcie worker 注册失败");
}); }
// sw.js
// 监听 `install` 事件,回调中缓存所需⽂件
self.addEventListener("install", e => {
e.waitUntil(
caches.open("my-cache").then(function(cache) {
return cache.addAll(["./index.html", "./index.js"]);
})
); });
// 拦截所有请求事件
// 如果缓存中已经有请求的数据就直接⽤缓存,否则去请求数据
self.addEventListener("fetch", e => {
e.respondWith(
caches.match(e.request).then(function(response) {
if (response) {
return response;
}
console.log("fetch source");
})
); });

打开⻚⾯,可以在开发者⼯具中的 Application 看到 Service Worker 已 经启动了

在 Cache 中也可以发现我们所需的⽂件已被缓存

当我们重新刷新⻚⾯可以发现我们缓存的数据是从 Service Worker 中读 取的

5 渲染机制

浏览器的渲染机制⼀般分为以下⼏个步骤

处理 HTML 并构建 DOM 树。处理 CSS 构建 CSSOM 树。将 DOM 与 CSSOM 合并成⼀个渲染树。根据渲染树来布局,计算每个节点的位置。 调⽤ GPU 绘制,合成图层,显示在屏幕上

在构建 CSSOM 树时,会阻塞渲染,直⾄ CSSOM 树构建完成。并且构建 CSSOM 树是⼀ 个⼗分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选 择器,执⾏速度越慢 当 HTML 解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地⽅重新开始。 也就是说,如果你想⾸屏渲染的越快,就越不应该在⾸屏就加载 JS ⽂件。并且 CSS 也会
影响 JS 的执⾏,只有当解析完样式表才会执⾏ JS,所以也可以认为这种情况下,CSS 也 会暂停构建 DOM

⼀般来说,可以把普通⽂档流看成⼀个图层。
特定的属性可以⽣成⼀个新的图层。
不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议
单独⽣成⼀ 个新图层,提⾼性能。
但也不能⽣成过多的图层,会引起反作⽤

通过以下⼏个常⽤属性可以⽣成新图层

3D 变换: translate3d 、 translateZ
will-change
video 、 iframe 标签
通过动画实现的 opacity 动画转换
position: fixed

重绘(Repaint)和回流(Reflow)
重绘是当节点需要更改外观⽽不会影响布局的,⽐如改变 color 就叫称为重绘 回流是布局或者⼏何属性需要改变就称为回流

回流必定会发⽣重绘,重绘不⼀定会引发回流。
回流所需的成本⽐重绘⾼的多,
改变深层次的节点很可能导致⽗节点的⼀系列回流

所以以下⼏个动作可能会导致性能问题:

改变 window ⼤⼩改变字体 添加或删除样式 ⽂字改变定位或者浮动 盒模型

很多⼈不知道的是,重绘和回流其实和 Event loop 有关

当 Event loop 执⾏完 Microtasks 后,会判断 document 是否需要更新。
因为浏览 器是 60Hz 的刷新率,每 16ms 才会更新⼀次。然后判断是否有 resize 或者 scroll ,有的话会去触发事件,所以 resize 和
scroll 事件也是⾄少 16ms 才会触发⼀次,并且⾃带节流功能。
判断是否触发了 media query
更新动画并且发送事件
判断是否有全屏操作事件
执⾏ requestAnimationFrame 回调
执⾏ IntersectionObserver 回调,该⽅法⽤于判断元素是否可⻅,
可以⽤于懒加载上,但是兼容性不好。
更新界⾯
以上就是⼀帧中可能会做的事情。如果在⼀帧中有空闲时间,就会去执⾏
requestIdleCallback 回调

减少重绘和回流

使⽤ translate 替代 top
使⽤ visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局) 不要使⽤ table 布局,可能很⼩的⼀个⼩改动会造成整个 table 的重新布局
动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使⽤
requestAnimationFrame
CSS 选择符从右往左匹配查找,避免 DOM 深度过深
将频繁运⾏的动画变为图层,图层能够阻⽌该节点回流影响别的元素。
⽐如对于 video
标签,浏览器会⾃动将该节点变为图层

三、性能

1 DNS 预解析

DNS 解析也是需要时间的,可以通过预解析的⽅式来预先获得域名所对应的 IP

<link rel="dns-prefetch" href="//blog.poetries.top">

2 缓存

缓存对于前端性能优化来说是个很重要的点,良好的缓存策略可以降低资源的重复加载提 ⾼⽹⻚的整体加载速度 通常浏览器缓存策略分为两种:强缓存和协商缓存
强缓存
实现强缓存可以通过两种响应头实现: Expires 和 Cache-Control 。强缓 存表示在缓存期间不需要请求, state code 为 200

Expires: Wed, 22 Oct 2018 08:41:00 GMT

Expires 是 HTTP / 1.0 的产物,表示资源会在 Wed, 22 Oct 2018
08:41:00 GMT 后过期,需要再次请求。并且 Expires 受限于本地时间,如 果修改了本地时间,可能会造成缓存失效

Cache-control: max-age=30

Cache-Control 出现于 HTTP / 1.1 ,优先级⾼于 Expires 。
该属性表示资源会在 30 秒后过期,需要再次请求
协商缓存

如果缓存过期了,我们就可以使⽤协商缓存来解决问题。协商缓存需要请求,
如果缓存有 效会返回 304
协商缓存需要客户端和服务端共同实现,和强缓存⼀样,也有两种实现⽅式

Last-Modified 和 If-Modified-Since
Last-Modified 表示本地⽂件最后修改⽇期, If-Modified-Since 会将 LastModified 的值发送给服务器,
询问服务器在该⽇期后资源是否有更新,有更新的话就会将 新的资源发送回来
但是如果在本地打开缓存⽂件,就会造成 Last-Modified 被修改,
所以在 HTTP /
1.1 出现了 ETag
ETag 和 If-None-Match
ETag 类似于⽂件指纹, If-None-Match 会将当前 ETag 发送给服务器,
询问该资源 ETag 是否变动,有变动的话就将新的资源发送回来。
并且 ETag 优先级⽐ LastModified ⾼
选择合适的缓存策略

对于⼤部分的场景都可以使⽤强缓存配合协商缓存解决,
但是在⼀些特殊的地⽅可能需要选择特殊的缓存策略

对于某些不需要缓存的资源,可以使⽤ Cache-control: no-store ,
表示该资源不需要缓存
对于频繁变动的资源,可以使⽤ Cache-Control: no-cache 并配合 ETag 使⽤,
表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
对于代码⽂件来说,通常使⽤ Cache-Control: max-age=31536000 并配合策略缓存使 ⽤,然后对⽂件进⾏指纹处理,⼀旦⽂件名变动就会⽴刻下载新的⽂件

3 使⽤ HTTP / 2.0

因为浏览器会有并发请求限制,在 HTTP / 1.1 时代,每个请求都需要建⽴和断开,
消耗 了好⼏个 RTT 时间,并且由于 TCP 慢启动的原因,
加载体积⼤的⽂件会需要更多的时 间在 HTTP / 2.0 中引⼊了多路复⽤,
能够让多个请求使⽤同⼀个 TCP 链接,极⼤的加 快了⽹⻚的加载速度。
并且还⽀持 Header 压缩,进⼀步的减少了请求的数据⼤⼩

4 预加载

在开发中,可能会遇到这样的情况。有些资源不需要⻢上⽤到,
但是希望尽早获取,这时 候就可以使⽤预加载 预加载其实是声明式的 fetch ,
强制浏览器请求资源,并且不会阻塞 onload 事件,
可以使⽤以下代码开启预加载、

<link rel="preload" href="http://example.com">

预加载可以⼀定程度上降低⾸屏的加载时间,
因为可以将⼀些不影响⾸屏但重要的⽂件延后加载,唯⼀缺点就是兼容性不好
5 预渲染
可以通过预渲染将下载的⽂件预先在后台渲染,可以使⽤以下代码开启预渲染

<link rel="prerender" href="http://poetries.com">

预渲染虽然可以提⾼⻚⾯的加载速度,但是要确保该⻚⾯百分百会被⽤户在之后打开,否 则就⽩⽩浪费资源去渲染

6 懒执⾏与懒加载

懒执⾏
懒执⾏就是将某些逻辑延迟到使⽤时再计算。该技术可以⽤于⾸屏优化,对于某些耗时逻 辑并不需要在⾸屏就使⽤的,就可以使⽤懒执⾏。懒执⾏需要唤醒,⼀般可以通过定时器 或者事件的调⽤来唤醒
懒加载
懒加载就是将不关键的资源延后加载

懒加载的原理就是只加载⾃定义区域(通常是可视区域,
但也可以是即将进⼊ 可视区域)内需要加载的东⻄。
对于图⽚来说,先设置图⽚标签的 src 属性 为⼀张占位图,
将真实的图⽚资源放⼊⼀个⾃定义属性中,当进⼊⾃定义区域 时,
就将⾃定义属性替换为 src 属性,这样图⽚就会去下载资源,实现了图⽚懒加载

懒加载不仅可以⽤于图⽚,也可以使⽤在别的资源上。⽐如进⼊可视区域才开始播放视频 等

7 ⽂件优化

图⽚优化

对于如何优化图⽚,有 2 个思路

减少像素点
减少每个像素点能够显示的颜⾊
图⽚加载优化

不⽤图⽚。很多时候会使⽤到很多修饰类图⽚,
其实这类修饰图⽚完全可以⽤ CSS 去代 替。对于移动端来说,屏幕宽度就那么点,
完全没有必要去加载原图浪费带宽。⼀般图⽚都⽤ CDN 加载,
可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图⽚⼩图使⽤ base64 格式
将多个图标⽂件整合到⼀张图⽚中(雪碧图) 选择正确的图⽚格式:对于能够显示 WebP 格式的浏览器尽量使⽤ WebP 格式。因为 WebP 格式具有更好 的图像数据压缩算法,能带来更⼩的图⽚体积,⽽且拥有⾁眼识别⽆差异的图像质量, 缺点就是兼容性并不好⼩图使⽤ PNG ,其实对于⼤部分图标这类图⽚,完全可以使⽤ SVG 代替照⽚使⽤ JPEG

其他⽂件优化

CSS ⽂件放在 head 中 服务端开启⽂件压缩功能将 script 标签放在 body 底部,
因为 JS ⽂件执⾏会阻塞渲染。当然也可以把script 标签放在任意位置
然后加上 defer ,表示该⽂件会并⾏下载,但是会放到HTML 解析完成后顺序执⾏。
对于没有任何依赖的 JS ⽂件可以加上 async ,表示加 载和渲染后续⽂档元素的过程
将和 JS ⽂件的加载与执⾏并⾏⽆序进⾏。 执⾏ JS 代码 过⻓会卡住渲染,
对于需要很多时间计算的代码 可以考虑使⽤ Webworker 。Webworker 可以让我们另开⼀个线程执⾏脚本⽽不影响渲染。

CDN

静态资源尽量使⽤ CDN 加载,由于浏览器对于单个域名有并发请求上限,
可 以考虑使⽤多个 CDN 域名。对于 CDN 加载静态资源需要注意 CDN 域名
要与主站不同,否则每次请求都会带上主站的 Cookie

8 其他

使⽤ Webpack 优化项⽬
对于 Webpack4 ,打包项⽬使⽤ production 模式,这样会⾃动开启代码压缩
使⽤ ES6 模块来开启 tree shaking ,这个技术可以移除没有使⽤的代码优化图⽚,
对于⼩图可以使⽤ base64 的⽅式写⼊⽂件中
按照路由拆分代码,实现按需加载 给打包出来的⽂件名添加哈希,
实现浏览器缓存⽂件
监控

对于代码运⾏错误,通常的办法是使⽤ window.onerror 拦截报错。该⽅法 能拦截到⼤部分的详细报错信息,但是也有例外

对于跨域的代码运⾏错误会显示 Script error .
对于这种情况我们需要给 script 标签添加 crossorigin 属性
对于某些浏览器可能不会显示调⽤栈信息,这种情况可以
通过arguments.callee.caller 来做栈递归
对于异步代码来说,可以使⽤ catch 的⽅式捕获错误。
⽐如 Promise 可以直接使⽤ catch 函数, async await 可以使⽤ try catch
但是要注意线上运⾏的代码都是压缩过的,
需要在打包时⽣成 sourceMap ⽂件便于
debug 。 对于捕获的错误需要上传给服务器,
通常可以通过 img 标签的 src 发起⼀个请求

每日一句中文式外语

法语

你好,我叫XXX
笨猪,热辣木屋XX(一头笨猪,在热辣的木屋里,那头笨猪就是XXX)
【哈哈!好吧,我笑了,这个联想记忆太骚了哈哈哈】

关于浏览器的那些事情1【面试】相关推荐

  1. 前端基础-浏览器缓存/HTTP缓存机制(面试常考)

    文章目录 一.HTTP报文 1.HTTP请求(Request)报文 2.HTTP响应(Response)报文 二.缓存过程分析 三.缓存规则 1.强制缓存 1.1Expires 1.2 Cache-C ...

  2. 常见浏览器的兼容性问题(面试重点)

    众所周知,浏览器的兼容性问题是开发人员经常会遇到的问题,它是由于不同浏览器的不同对代码的解析不同,而产生的在页面上显示的效果不同.那么,现在我把从工作当中发遇到的有关兼容性问题及解决方案做个简单总结, ...

  3. 面试:你觉得自己做过最失败的一件事情是什么?

    很多求职者在面试的时候都会给面试官问到:你觉得自己做过最失败的一件事情是什么?你知道面试官问你这个问题的主要目的是什么吗?你要怎么回答才能出色的表现自己呢?今天珠海人才网给你分享关于面试中回答自己最失 ...

  4. serversocket 返回浏览器图片_深入理解浏览器的缓存机制

       戳蓝字「前端技术优选」关注我们哦! 一.前言 缓存可以说是性能优化中简单高效的一种优化方式了.一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽 ...

  5. 阿里面试:“说一下从 url 输入到返回请求的过程”

    作者 | 孟祥_成都 来源 | https://juejin.cn/post/6928677404332425223 前言 年前准备换工作,总结了一波面试最频繁的面试问题跟大家交流.此文章是关于浏览器 ...

  6. 宇宙现场面试题目实录

    面试:神州数码 1.介绍你下你项目中一个自动化实现的流程   ==>看这篇软件测试培训_软件测试培训班_it培训_BI大数据_多测师 2.你觉得做自动化的意义在哪里    ==>需要对之前 ...

  7. 前端面试相关题(简易)

    HTML ,CSS相关 1.网络中使用最多的图片格式有哪些 JPEG,GIF,PNG,最流行的是jpeg格式,可以把文件压缩到最小 在ps以jpeg格式存储时,提供11级压缩级别 2.请简述css盒子 ...

  8. 阿里面试官的 说一下从url输入到返回请求的过程 问的难度就是不一样!

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:推荐19个github超牛逼项目!个人原创100W +访问量博客:点击前往,查看更多 来源:juejin.cn/p ...

  9. 面试总结及相关知识点汇总

    最近因为离职,又因为在原来的公司也担任"要职",所以尝试了面试者和被面试者两个不同的角色,闲来无事,就来总结下这期间的心得,以及这期间所整理的博客. 首先申明该心得不主要是为面试者 ...

最新文章

  1. 数据结构与算法之美-目录
  2. Debian 3.1 (Sarge) 正式发布,Knoppix也升级到最后一个单CD版3.9
  3. 使用 TABLESAMPLE 限制结果集
  4. cocostuff10k数据集介绍_(六)COCO数据集的简单介绍
  5. 看完这篇,java遍历字符串列表
  6. 存储过程(简单入门)
  7. Nginx 配置虚拟主机
  8. 拜托!你只会用 ! = null 判空?
  9. mod_shout 模块
  10. 生成发布包_制作R包指南
  11. Appium1.22.3下载安装与配置
  12. 递归函数python有什么特点_递的笔顺 笔画数:10 拼音:dì 部首:辶 - 智慧山
  13. php点击按钮保存图片到相册,手机端点击下载按钮将页面保存成图片到本地
  14. 网络环路导致公司网络瘫痪问题排查
  15. 极简OpenFoam编程
  16. Newt Scamander的恐惧
  17. QML用径向渐变做波纹效果
  18. c++ 问题:查找预编译头时遇到意外的文件结尾
  19. 蓝牙耳机连Stereo mode上win10后没有声音?
  20. 选择器和字体的设置7.22

热门文章

  1. php 查找所有函数,PHP(方法 函数 循环 和 数组 查找)
  2. 如何做到注册不到三年Github标星47.1k+(几点经验)
  3. 搭载“可信隐私沙盒”技术 蚂蚁集团联合荣耀手机从源头防范电信诈骗
  4. 联名款Redmi K40游戏增强版今日揭晓:神秘女主粉色头发吸睛
  5. 一年换7家公司,95后跳槽多疯狂
  6. 一加9系列全网预约量破200万:3月24日见!
  7. 苹果2021年WWDC大会可能继续采用线上方式举办
  8. 明天上线!部分开发者手机已安装鸿蒙OS:超流畅,可装安卓应用
  9. 当半个娱乐圈都在吃自嗨锅,方便面去哪儿了?
  10. 胡祖六回应“低价转让蚂蚁股权”一事:有误会 之后择时澄清