前言
本次主要搬运神策数据公司以及其他面试的常问问题
文章目录
- 前言
- 问题总结
- 前端向后台发送请求有几种方式?
- 在div中添加一个行内元素要怎么添加?
- GET 和 POST 的区别?
- 多个异步任务如何同步执行?
- 引入JS文件有什么方式?
- 在一个JS文件中引入另外的一个JS文件?
- 有一个页面,要发50个请求,你会怎么优化?
- 后端一次性传了10w条数据,前端该如何处理?
- 一次连接有没有请求的限制
- 用户反馈一个界面加载太慢了,你会用什么工具去分析页面慢的原因是什么,以及解决方案是什么?
- 页面大量图片如何进行加载速度优化?
- link和import区别
- proxy和object.defineproperty的区别与联系?
- Promise对象和generator的使用场景
- 如何通过webpack实现分块打包
- 一个TCP连接能发多少个http请求?
- HTML5语义化的意义
- 做过自适应吗?
- rem为什么可以自适应?
- em的大小相对于谁?
- 讲一下flex与grid布局。
- flex能给详细讲一下吗?如何竖向排列?
- 能给讲一下原型与原型链吗?
- v-for使用过吗?要不要加key属性?为什么要加?
- diff算法的简单原理说了一下?
- 单页面(SPA)与多页面?单页面优缺点?
- 全局作用域中,用 const 和 let 声明的变量存到了哪里?
- call与apply的区别?
- 浏览器缓存机制
- 监听滚动条滚动应该用哪个(防抖和节流)?
- 页面渲染的过程
- http请求的类型,除了GET、POST外,还有什么?
- webpack的loader是怎么工作的?输入输出是什么?sass文件是怎么转成css文件的?
- 页面上的图片是在什么时候进行加载?
- html中的img和css中的img有什么不同?
- script标签中的async和defer有什么不同?
- base64转换图片,为什么会有尺寸的限制?为什么base64转换后,体积会变大?
- Cookie、 LocalStorage 与 SessionStorage?
问题总结
前端向后台发送请求有几种方式?
① Link标签的href属性
② Script标签的src属性
③ Img标签的src属性
④ Ajax发送请求
⑤ 表单提交发送请求
⑥ a标签的href属性
⑦ Iframe的src属性
在div中添加一个行内元素要怎么添加?
<div>
<ul>
</ul>
</div>
<style>
div {
background-color: pink;
}
</style>
<script>
let ul = document.querySelector('ul'); //获取父元素
let li = document.createElement('li'); //获取子元素
li.innerText = '子元素'; //给子元素添加文字
ul.appendChild(li) //插入到父元素中
</script>
GET 和 POST 的区别?
GET和POST,两者是HTTP协议中发送请求的方法
-
GET
GET方法请求一个指定资源的表示形式,使用GET的请求应该只被用于获取数据 -
POST
POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用
本质上都是TCP链接,并无差别
但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中会体现出一些区别
- 区别
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中
面试官:说一下 GET 和 POST 的区别?
多个异步任务如何同步执行?
(这里也可以用promise.all)
要求:异步函数之间有关联关系;前一个异步函数的输出作为后一个异步函数的输入;
在做异步函数之间有关联关系之前,先来做一下同步函数的执行,前面一个同步函数的输出作为后面一个同步函数的输入
const add = x => x + 5;
const multiply = (x) => x * 5;
const subtraction = x => x - 5;
const division = x => x / 5;
const targetFn = pipeFunctions(
add, //10
multiply, //50
subtraction, //45
division //9
);
targetFn(5);
我们执行 targetFn希望最后的结果是9,那么这个 pipeFunctions该怎么实现呢?
pipeFunctions会接收参数,但是我们也不知道有多少个,所以使用扩展运算符。前一轮结束的结果作为下面一个的输入,我们可以采用reduce方法(reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。)reduce函数有四个参数
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数 | 含义 |
---|---|
total 必需 | 初始值, 或者计算结束后的返回值。 |
currentValue | 必需。当前元素 |
currentIndex | 可选。当前元素的索引 |
arr | 当前元素所属的数组对象。 |
我们这个里面的reduce接收的第一个参数是一个回调函数,第二个是回调函数的初始值,此时我们的参数为(preFn,curFn),preFn表示上一轮函数,比如我们的add,curFn表示当前的函数。在这个方法里面,他是需要函数调用的,所以就需要返回一个函数,因为我们要在函数里面执行,而且下一轮的结果也是一个函数。这个函数同样我们也不知道参数是多少个,所以也要给一个扩展运算符。接下来要执行这个函数,将上一轮的函数执行res = preFn(…args),得到上一轮的结果res,再将这个结果放到当前执行。做成了一个链式调用的效果。
// reduce
fns.reduce((preFn, curFn) => {
return (..args) => {
const res = preFn(...args);
return curFn(res);
};
};
整体代码如下:
const add = x => x + 5;
const multiply = (x) => x * 5;
const subtraction = x => x - 5;
const division = x => x / 5;
const pipeFunctions = (...fns) => {
// reduce
return fns.reduce((preFn, curFn) => {
return (...args) => {
const res = preFn(...args);
return curFn(res);
};
})
}
const targetFn = pipeFunctions(
add,
multiply,
subtraction,
division
);
console.log(targetFn(5)); //9
异步的话:
//异步
//模拟一下异步的随机的时间戳,代表异步执行的时间
const asyncFn = (v) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(v);
}, Math.random() * 1000);
});
};
const add2 = async x => await asyncFn(x + 5);
const multiply2 = async(x) => await asyncFn(x * 5);
const subtraction2 = async x => await asyncFn(x - 5);
const division2 = async x => await asyncFn(x / 5);
const targetFn2 = pipeFunctions2(
add2,
multiply2,
subtraction2,
division2
);
targetFn2(5); //9
这里最关键的就是对于pipeFunctions2函数的编写,它的参数同样是不定的,同样使用reduce方法,参数同上。返回的时候是需要对preFn执行的,preFn它还是一个异步函数,所以我们返回的时候要加上async
引入JS文件有什么方式?
Script标签引入方式:4种
1.script的标签
<script>
var str1 = "123";
console.log(str1);//控制台打印
</script>
2.a标签引入
<a href="javascript:alert('hah')">sdfsdf</a>
3.div后面引入
<div onclick="alert('我被点击了')"></div>
//直接在后面写点击事件
4.script引入JS文件
<script src="js/nihao.js"></script>
在一个JS文件中引入另外的一个JS文件?
方法一,在调用文件的顶部加入下例代码
document.createElement("script").setAttribute("src", "render.js");
方法二,在调用文件的顶部加入下例代码
function addScript(url){
document.write("< script language=javascript src="+url+"></ script>");
}
方法三,在js中写如下代码:
function addScript(url){
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src',url);
document.getElementsByTagName('head')[0].appendChild(script);
}
利用document.createElement(”script”)生成了一个script的标签,设置其 type属性text/javascript。
方法四,利用es6中export和import实现模块化
一个js文件代表一个js模块 。ES6引入外部模块分两种情况:
1.导入外部的变量或函数等;
import {firstName, lastName} from './test';
2.导入外部的模块,并立即执行
import './test' //执行test.js,但不导入任何变量
详情参考:js文件中引入js的方法
有一个页面,要发50个请求,你会怎么优化?
看功能和触发方式,异步请求处理必要性高的,使用 promise 处理关联性强的,非必要接口懒加载,散碎的最好让后端进行接口整合,也可以用 promiseall 来处理,交互性接口考虑截流和防抖,避免重复加载,交互密集度高的可以考虑使用长连接或者 socket,展示数据根据需求考虑预先加载进行本地缓存。
还可以考虑
- 多路复用
多路复用(multiplexing),简称复用,是通信技术中的基本概念 。
(多路复用是指在一条物理信道上同时传输多路信息。多路复用是数据通信的一个常用技术,解决如何在单一的物理通道线路上建立多条并行通信信道的问题;)
老师提示 :那可不可以升级http? - 在 HTTP1.0 中,每一次 HTTP 请求都会创建一个 TCP 连接,在请求发送完成,服务器响应以后,这个 TCP 连接就自动断开了。
- 在 HTTP1.1 中,可以通过手动设置 Connection: keep-alive 请求头来建立 TCP 的持久连接,多个 HTTP 请求可以共用一个 TCP 连接。但是 TCP 连接存在线头阻塞,即若干个请求排队等待发送,一旦有某请求超时等,后续请求只能被阻塞。
- 在 HTTP2.0 中,采用了信道复用,使 TCP 连接支持并发请求,即多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行吗,这样一来,大部分请求可以使用一个 TCP 连接,而不用创建新的 TCP 连接通道,既节省了三次握手的开销,又节约了服务端维护 TCP 端口的成本。
那升级之前,可以把50个请求变成10个请求吗?
我说:可以
做一个中间件,将5个请求合并为1个请求。50个请求就会变成10个请求。将请求集成。或者和后端去沟通,去把接口优化
后端一次性传了10w条数据,前端该如何处理?
一次连接有没有请求的限制
有的,CHROME浏览器发送HTTP最大请求并发数限制
①同一域名下,同一GET请求的并发数是1,也就是说上一个请求结束,才会执行下一个请求,否则置入队列等待发送;
②同一域名下,不同GET/POST请求的并发数量是6。当发送的请求数量达到6个,并且都没有得到响应时,后面的请求会置入队列等待发送。
用户反馈一个界面加载太慢了,你会用什么工具去分析页面慢的原因是什么,以及解决方案是什么?
如何分析页面加载慢?
我知道有分析加载js文件和css文件时间的工具,可以通过这个工具去看哪类文件的问题
老师说:其实控制台就可以看到
解决方案,第一个路由懒加载
第二个 js文件放到底部
老师追问:放到底部,如果js文件里有大量的计算,还会阻塞界面吗
我说:会
老师问:那怎么解决,
我说:异步记载,
老师说:还有没有其他方案,我没答上来。他说,js是单线程,可以考虑在开一个线程专门加载js文件,比如webWorker,这个你下去可以再学一下
网路请求还可以优化吗
我回答:内容分发网络(CDN)
注:内容分发网络的原理:
通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN 系统能够实时地根据 网络流量 和 各节点的连接、负载状况 以及 到用户的距离 和 响应时间 等综合信息将用户的请求重新导向离用户最近的服务节点上。比如:
页面大量图片如何进行加载速度优化?
前端性能优化-优化大量图片加载&超大图片加载(附懒加载实现方案)
link和import区别
proxy和object.defineproperty的区别与联系?
- Proxy是对整个对象的代理,而Object.defineProperty只能代理某个属性。
- 对象上新增属性,Proxy可以监听到,Object.defineProperty不能。
- 数组新增修改,Proxy可以监听到,Object.defineProperty不能。
- 若对象内部属性要全部递归代理,Proxy可以只在调用的时候递归,而Object.definePropery需要一次完成所有递归,性能比Proxy差。
- Proxy不兼容IE,Object.defineProperty不兼容IE8及以下
- Proxy使用上比Object.defineProperty方便多。
Promise对象和generator的使用场景
promise和generator主要都是处理异步请求,如果访问的内容元素固定,两者写法类似,其差别不大。Promise适合一次读一堆固定格式的数据,generator适合读具有逻辑性的数据。
如何通过webpack实现分块打包
- 读取webpack的配置文件
- 启动webpack,创建complier对象,开始解析项目;
- 从入口文件(entry)开始解析,找到其导入的依赖模块,递归遍历分析,形成依赖关系树;
- 对不同文件类型的依赖模块文件使用对应的loader进行编译,转化为js代码
- 整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。
一个TCP连接能发多少个http请求?
HTML5语义化的意义
- 方便SEO。
- 方便无障碍阅读,对于帮助视力障碍者阅读的设备筛选重要数据有帮助。
- 方便开发者维护代码。
- 当丢失层叠样式表的时候,页面也会按照语义化布局显式。
做过自适应吗?
可以用媒体查询。
可以使用rem或者vh、vw相对单位
rem为什么可以自适应?
rem相对于body标签的字体大小,如果body的font-size:16px;那么1rem = 16px
em的大小相对于谁?
相对于父级元素。(当时答错了!)
讲一下flex与grid布局。
flex与grid是css3新增的布局属性。分别为了解决:一维与二维的布局缺陷。
flex能给详细讲一下吗?如何竖向排列?
flex存在两条轴:水平主轴、竖直交叉轴。
默认项目不换行在主轴上水平排列,可以使用flex-direction: column;使其竖直排列。
能给讲一下原型与原型链吗?
v-for使用过吗?要不要加key属性?为什么要加?
key可以体改虚拟dom的更新效率。
在vue中默认“就地复用”的策略,在DOM操作时,如果没有key就会造成选项错乱。
key只能是字符串或者num;
diff算法的简单原理说了一下?
单页面(SPA)与多页面?单页面优缺点?
SPA单页面应用(SinglePage Web Application) ,指只有一个主页面的应用(一个html页面),一开始只需要加载一次js、css的相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源。
MPA多页面应用(MultiPage Application) ,指有多个独立页面的应用(多个html页面),每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新。
- 单页面优点:
1.良好的交互体验
单页应用的内容的改变不需要重新加载整个页面,获取数据也是通过Ajax异步获取,没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象,页面显示流畅,web应用更具响应性和更令人着迷。
2.良好的前后端工作分离模式
后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。
3.减轻服务器压力
单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。 - 单页面缺点
1.首屏加载慢
如果不对路由进行处理,在加载首页的时候,就会将所有组件全部加载,并向服务器请求数据,这必将拖慢加载速度;
解决方案:
Vue-router懒加载(Vue-router懒加载就是按需加载组件,只有当路由被访问时才会加载对应的组件,而不是在加载首页的时候就加载,项目越大,对首屏加载的速度提升得越明显。)
使用CDN加速(在做项目时,我们会用到很多库,采用cdn加载可以加快加载速度。)
异步加载组件(这里可以参考别人的介绍(https://segmentfault.com/a/1190000012138052)
服务端渲染(服务端渲染还能对seo优化起到作用,有利于搜索引擎抓取更多有用的信息(如果页面纯前端渲染,搜索引擎抓取到的就只是空页面)
2.不利于SEO
seo 本质是一个服务器向另一个服务器发起请求,解析请求内容。但一般来说搜索引擎是不会去执行请求到的js的。也就是说,搜索引擎的基础爬虫的原理就是抓取url,然后获取html源代码并解析。 如果一个单页应用,html在服务器端还没有渲染部分数据数据,在浏览器才渲染出数据,即搜索引擎请求到的html是模型页面而不是最终数据的渲染页面。 这样就很不利于内容被搜索引擎搜索到。
解决方案:
服务端渲染(服务器合成完整的 html 文件再输出到浏览器)
页面预渲染(路由采用h5 history模式)
3.不适合开发大型项目
大型项目中可能会涉及大量的DOM操作、复杂的动画效果,也就不适合使用Vue、react框架进行开发
单页面应用程序(SPA)的优缺点
全局作用域中,用 const 和 let 声明的变量存到了哪里?
var a = 10;
function f(){};
console.log(window.a); // 10
console.log(window.f); // f(){}
但是
let a = 1;
const b = 2;
console.log(window.a); // undefined
console.log(window.b); // undefined
通过上图也可以看到,在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中。
结论:
使用 let / const 声明的全局变量,会被绑定到Script对象而不是Window对象,不能以Window.xx 的形式使用;使用 var 声明的全局变量会被绑定到Window对象;使用var / let / const 声明的局部变量都会被绑定到 Local 对象。注:Script对象、Window对象、Local对象三者是平行并列关系。
JavaScript中的global对象,window对象以及document对象的区别和联系
call与apply的区别?
bind和call、apply有什么作用?它们的区别是什么?
浏览器缓存机制
浏览器缓存的全过程:
- 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;
- 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;
- 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match和 If-Modified-Since 的请求;
- 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
- 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;
监听滚动条滚动应该用哪个(防抖和节流)?
利用函数节流实现监听滚动条停止.函数节流的基本思想是设置一个定时器,在指定时间间隔内运行代码时清楚上一次的定时器,并设置另一个定时器,直到函数请求停止并超过时间间隔才会执行。
页面渲染的过程
http请求的类型,除了GET、POST外,还有什么?
序号 | 方法 | 描述用途 |
---|---|---|
1 | GET | 【获取资源】本质就是发送一个请求来取得服务器上的某一资源。资源通过一组HTTP头和呈现数据(如HTML文本,或者图片或者视频等)返回给客户端。GET请求中,永远不会包含呈现数据。 即GET请求只用来向服务器获取资源,而GET请求本身不应该携带任何呈现数据。1. 登录时GET获取服务器数据库用户名和密码进行验证。2.下载文本、图片、音视频等时获取服务器资源。 |
2 | POST | 【传输实体文本】向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在POST请求体中。POST 请求可能会导致新的资源的建立或已有资源的修改。1. 提交用户注册信息。2. 提交修改的用户信息。 |
3 | HEAD | 【获得报文首部】类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头。欲判断某个资源是否存在,我们通常使用GET,但这里用HEAD则意义更加明确。1. 向服务器获取某些易过期或丢失大型文件时,可用HEAD方式查询资源是否存在。 |
4 | OPTIONS | 【询问支持的方法】客户端询问服务器可以提交哪些请求方法。这个方法很有趣,它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST”。极少使用。 |
5 | PUT | 【传输文件】从客户端向服务器传送的数据取代指定的文档的内容,即指定上传资源存放路径。这个方法比较少见。HTML表单也不支持这个。本质上来讲, PUT和POST极为相似,都是向服务器发送数据,但它们之间有一个重要区别,PUT通常指定了资源的存放位置,而POST则没有,POST的数据存放位置由服务器自己决定。如一个用于提交博文的URL,/addBlog。如果用PUT,则提交的URL会是像这样的”/addBlog/abc123”,其中abc123就是这个博文的地址。而如果用POST,则这个地址会在提交后由服务器告知客户端。目前大部分博客都是这样的。显然,PUT和POST用途是不一样的。具体用哪个还取决于当前的业务场景。 |
6 | PATCH | 【局部更新文件】是对 PUT 方法的补充,用来对已知资源进行局部更新 。极少使用。 |
7 | DELETE | 【删除文件】请求服务器删除指定的资源。基本上这个也很少见,不过还是有一些地方比如amazon的S3云服务里面就用的这个方法来删除资源。 |
8 | TRACE | 【追踪路径】回显服务器收到的请求,客户端可以对请求消息的传输路径进行追踪,TRACE方法是让Web服务器端将之前的请求通信还给客户端的方法。主要用于测试或诊断。极少使用。 |
9 | CONNECT | 【要求用隧道协议连接代理】HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经网络隧道传输。极少使用。 |
webpack的loader是怎么工作的?输入输出是什么?sass文件是怎么转成css文件的?
webpack 本身只能处理 JavaScript 和 JSON 文件,而 loader 为 webpack 添加了处理其他类型文件的能力。loader 将其他类型的文件转换成有效的 webpack modules(如 ESmodule、CommonJS、AMD),webpack 能消费这些模块,并将其添加到依赖关系图中。
loader 本质上是一个函数,该函数对接收到的内容进行转换,返回转换后的结果。
常见的 loader 有:
- raw-loader:加载文件原始内容。
- file-loader:将引用文件输出到目标文件夹中,在代码中通过相对路径引用输出的文件。
- url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式将文件内容注入到代码中。
- babel-loader:将 ES 较新的语法转换为浏览器可以兼容的语法。
- style-loader:将 CSS 代码注入到 JavaScript 中,通过 DOM 操作加载 CSS。
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性。
使用 loader 的方式主要有两种:
- 在 webpack.config.js 文件中配置,通过在 module.rules 中使用 test 匹配要转换的文件类型,使用 use 指定要使用的 loader。
module.exports = {
module: {
rules: [{ test: /\.ts$/, use: "ts-loader" }],
},
};
- 内联使用
import Styles from "style-loader!css-loader?modules!./styles.css";
Loader 的输入和输出:
输入:
/**
* @param {string|Buffer} content 源文件的内容
* @param {object} [map] 可以被 https://github.com/mozilla/source-map 使用的 SourceMap 数据
* @param {any} [meta] meta 数据,可以是任何内容
*/
function loader(content, map, meta) {
}
- content:必选,上一个 loader 的输出。对于第一个 loader 而言,只有只一个入参,其输入是资源文件的内容。
- map:可选,SourceMap 数据。
- meta:可选,元数据,可以是任何内容,用于 loader 之间传递额外信息,Webpack 不会对其做处理。
Loader 的输出?
loader 的返回的结果应该是 String 或者 Buffer 类型(可以被转成 String 类型)。
对于最后一个 loader 而言,其结果代表了模块的 JavaScript 源码,即 JavaScript 代码字符串。这个结果会传给 Webpack Compiler 进行下一步的处理。
手写一个 Webpack Loader
SASS(英文全称:Syntactically Awesome Stylesheets)Sass 诞生于 2007 年,使用Ruby 编写,是一种对css的一种扩展提升,增加了规则、变量、混入、选择器、继承等等特性。可以理解为用js的方式去书写,然后编译成css。比如说,sass中可以把反复使用的css属性值定义成变量,然后通过变量名来引用它们,而无需重复书写这一属性值。
页面上的图片是在什么时候进行加载?
html中的img和css中的img有什么不同?
1、css中的图片以背景图形式存在,写在html中的图片以标签形式存在。而在网页加载过程中,以css背景存在的图片会等到html结构加载完成才开始加载,而html中的img标签是网页结构(内容)的一部分会在加载结构的过程中加载。
附:在一个单纯由Html和Css组成的页面中,背景图片总是最后加载的,那么假若我们想要使用较小的背景图片作为占位符,用于在加载较大的图片或者Flash文件时给用户以提示,大部分时候恐怕是达不到效果的,因为背景图片有时甚至会在大图片或Flash文件加载完成之后才会被加载。
2、通常非内容的图片(即用来修饰页面的元素)就写在css里,如果是内容性的图片就写在html中。比如,你要做一个漂亮相框的相册,那么修饰边框的图片就写在css里,相框里的内容照片就写在html中。
3、图片作为背景,在图片没有加载或者加载失败时,不会有个图片的占位标记,不会出现红叉。
script标签中的async和defer有什么不同?
script 是会阻碍 HTML 解析的,只有下载好并执行完脚本才会继续解析 HTML
defer 和 async有一个共同点:下载此类脚本都不会阻止页面呈现(异步加载),区别在于:
- async 执行与文档顺序无关,先加载哪个就先执行哪个;defer会按照文档中的顺序执行
- async 脚本加载完成后立即执行,可以在DOM尚未完全下载完成就加载和执行;而defer脚本需要等到文档所有元素解析完成之后才执行
base64转换图片,为什么会有尺寸的限制?为什么base64转换后,体积会变大?
打开google的首页,就能看到某些样式中的图片不是一个资源地址,而是base64编码的字符串,这么做有什么好处呢? 当然是减少了一次http的请求,但也并不是什么图片都适合用base64来处理,因为图片越大,转换的base64的字符串就越长,对带宽的要求更高了。
因为二进制补零了,6位变8位,总字节长度当然就膨胀了。
为什么Base64转码后,会比原文件大?