1、在你的项目中,你是如何实现响应式的,用了哪些方法?
开发基于react的news移动端web app,采用CSS3的Media Query,以rem这种相对字体大小单位作为宽度单位,适配不同分辨率的设备,如iPhone 5S、iPhone 6、iPhone 6S,在css文件中设置html元素的font-size,然后内嵌@media,分别对不同宽度进行适配,如:
@media screen and (min-width:321px) and (max-width:375px ) {
html{font-size: 50px;}
.carousel {
width: 375px;
}
.carousel img{
width: 100%;
height: 4rem;
}
.carousel .ant-carousel .slick-slider {
padding-bottom: 25px;
}
}
在index.html设置meta:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimu,-scale=1, user-scale=no">
2、什么是同源策略。哪些情况下不是同源的。例如a.baidu.com 与 baidu.com。
同源是指协议、域名、端口相同,只要有一种不同就不是同源的。
举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)。
它的同源情况如下:
http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
所以a.baidu.com和baidu.com域名不同,它们不是同源的。
目前,如果非同源,有三种行为受限制。
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
3、跨域怎么办?知道JSONP吗?它是怎么获取服务器发送过来的数据的?
比如要共享Cookie,如果是二级域名不同,如a.xxx.com和b.xxx.com,则可以通过设置相同的document.domain='xxx.com' ,在A页面的脚本设置document.cookie = 'test=hello',这时B页面就能读到该Cookie :var cookie = document.cookie;
JSONP最大特点就是简单适用,但只能用于GET方法。其基本思想是:在页面动态添加一个<script>标签,因为script请求不受限制,然后将要请求的地址放在src属性中,服务器收到请求后会将数据放在一个指定名字的回调函数里传回来。
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
请求地址中含有callback字段,后带回调函数的名字,获取数据作为其参数。
foo({
"ip": "8.8.8.8"
});
由script定义的标签,一旦放到html文本中就会立即执行。作为参数的JSON对象直接被视为JavaScript对象,因此省去了JSON.parse的步骤。
4、说一说HTTP有哪些状态码。
①2XX:请求成功
200 OK 表示被服务器正常处理
204 No Content 表示请求已成功处理,但没有内容返回(响应没有报文实体)
206 Partial Content 表示服务器已经完成了部分GET请求,响应报文中包含Content-Range指定范围的实体内容(先前的请求头包含Range)
②3XX:重定向
301 Moved Permanently 永久重定向,表示请求的资源已经永久的搬到了其他位置,就是说资源被分配了新的URI,放在Location首部字段
302 Found 临时重定向,表示请求的资源临时被配到了新的URI,未来还可能再改变
303 See Other 与302一样,只是明确规定客户端应该使用GET访问
304 Not Modified 表示客户端发送附带条件的请求(GET方法请求报文中的IF...)时,条件不满足,不包含任何响应主体
307 Temporary Redirect 临时重定向,意义和302相同,但会遵照标准,不会从POST变成GET
③4XX:客户端错误
400 Bad Request 表示请求报文存在语法错误或参数错误,服务器不理解,需要修改请求内容后再次发送
401 Unauthorized 表示发送的请求需要有HTTP认证信息或认证失败。返回401的响应必须包含一个适用于被请求资源的WWW-Authentication首部以质询用户信息,浏览器初次接受401时,会弹出认证窗口
403 Forbidden 表示对请求资源的访问被服务器拒绝了。可以在响应实体的主体部分描述原因,可能是以为没有访问权限
404 Not Found 服务器找不到请求的资源
④5XX:服务器错误
500 Internal Server Error 表示服务器执行请求的时候出错了,可能是Web应用自身的bug,或服务器源代码有bug
503 Service Unavailable 表示服务器超负载或正停机维护,无法处理请求,如果服务器知道还需要多长时间,就写入Retry-After首部字段返回
5、http有哪几种请求方式,GET和POST。分别在哪些情况下使用?
①GET 请求一个指定资源的表示形式,应该只被用于获取数据
从指定的资源(即被URI识别的资源)请求数据,指定的资源服务器解析后返回响应内容。请求服务器发送某个资源。可以带参数也可以不带参数, 带参数时,参数是明文传递,你可以在浏览器的地址栏中看到参数名及参数值,get安全性不高,所以常用于安全性要求低的场合, 比如登录后请求数据。
请求:
GET /index.html HTTP/1.1
Host: www.hackr.jp
响应: 返回 index.html 的页面资源
请求:
GET /index.html HTTP/1.1
Host: www.hackr.jp
If-Modified-Since: Thu, 12 Jul 2012 07:30:00 GMT
响应: 仅返回2012年7月12日7点30分以后更新过的index.html页面资源。
如果未有内容更新,则以状态码304 Not Modified作为响应返回
②POST 将来自客户端的数据存储到一个命名的服务器资源中去
向指定的资源提交要被处理的数据。
GET方法强调资源的获取,POST方法强调资源的传输。POST所传递的数据或参数不是已明文形式存在的,而是封装后的,因此相对安全系数高,像注册、登录、提交表单都是用该方法实现的。
请求:
POST /submit.cgi HTTP/1.1
Host: www.hackr.jp
Content-Length: 1560(1560字节的数据)
响应: 返回 submit.cgi 接收数据的处理结果
③PUT 传输文件
PUT 方法用来传输文件,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。
但是,鉴于 HTTP/1.1 的 PUT 方法自身不带验证机制,任何人都可以上传文件 , 存在安全性问题,因此一般的 Web 网站不使用该方法。若配合 Web 应用程序的验证机制,或架构设计采用 REST(REpresentationalState Transfer,表征状态转移)标准的同类 Web 网站,就可能会开放使用 PUT 方法。
请求:
PUT /example.html HTTP/1.1
Host: www.hackr.jp
Content-Type: text/html
Content-Length: 1560(1560 字节的数据)
响应: 响应返回状态码 204 No Content(比如:该html 已存在于服务器上)
POST与PUT比较:
这两个方法咋一看都可以更新资源,但是有本质区别的。
首先解释幂等,幂等是数学的一个用语,对于单个输入或者无输入的运算方法,如果每次都是同样的结果,则称其是幂等的。
对于两个参数,如果传入值相等,结果也等于每个传入值,则称其为幂等的,如max(a,b)
POST:
用于提交请求,可以更新或者创建资源,是非幂等的
举个例子,在我们的支付系统中,一个api的功能是创建收款金额二维码,它和金额相关,每个用户可以有多个二维码,如果连续调用则会创建新的二维码,这个时候就用POST。
PUT:
用于向指定的URI传送更新资源,是幂等的
还是那个例子,用户的账户二维码只和用户关联,而且是一一对应的关系,每次刷新账户的二维码都不变,此时这个api就可以用PUT。
④DELETE 从服务器中删除指定的资源(文件)
DELETE方法用来删除文件,是与PUT相反的方法。DELETE方法就是请求服务器删除请求URI所指定的资源。
但是,HTTP/1.1 的 DELETE方法本身和PUT方法一样不带验证机制,所以一般的Web 网站也不使用DELETE方法。当配合Web应用程序的验证机制,或遵守 REST 标准时还是有可能会开放使用的。
请求:
DELETE /example.html HTTP/1.1
Host: www.hackr.jp
响应: 响应返回状态码 204 No Content(比如:该 html 已从该服务器上删除)
⑤HEAD 仅发送命名资源响应中的HTTP头部
HEAD 方法和 GET 方法行为类似,只是不返回报文主体部分,只返回首部。
这就允许客户端在未获取实际资源的情况下,对首部进行检查,确认URI的有效性及资源更新的日期时间等。
请求:
HEAD /index.html HTTP/1.1
Host: www.hackr.jp
响应: 返回index.html有关的响应首部
⑥OPTIONS 用于描述目标资源的通信选项(CORS)
OPTIONS 方法请求服务器告知其支持的各种功能。可以用来查询针对请求 URI 指定的资源所支持的方法。
请求:
OPTIONS * HTTP/1.1
Host: www.hackr.jp
响应:
HTTP/1.1 200 OK
Allow: GET, POST, HEAD,
OPTIONS(返回服务器支持的方法)
CORS应用:
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
服务器收到"预检"请求以后,检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应。
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
上面的HTTP回应中,关键的是Access-Control-Allow-Origin
字段,表示http://api.bob.com
可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
⑦PATCH 用于对资源应用部分修改
⑧TRACE 用于演这目标资源的路径执行一个消息环回测试
⑨CONNECT 要求用隧道协议连接代理
CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。
主要使用SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
CONNECT 方法的格式如下所示:
CONNECT 代理服务器名:端口号 HTTP版本
请求:
CONNECT proxy.hackr.jp:8080
HTTP/1.1
Host: proxy.hackr.jp
响应:
HTTP/1.1 200 OK(之后进入网络隧道)
6、说一说cookie和webstorage。
上面提到的技术名词,都是在客户端以键值对存储的存储机制,并且只能将值存储为字符串。
cookie |
localStorage |
sessionStorage |
|
---|---|---|---|
由谁初始化 | 客户端或服务器,服务器可以使用Set-Cookie 请求头。 |
客户端 | 客户端 |
过期时间 | 手动设置 | 永不过期 | 当前页面关闭时 |
在当前浏览器会话(browser sessions)中是否保持不变 | 取决于是否设置了过期时间 | 是 | 否 |
是否随着每个 HTTP 请求发送给服务器 | 是,Cookies 会通过Cookie 请求头,自动发送给服务器 |
否 | 否 |
容量(每个域名) | 4kb | 5MB | 5MB |
访问权限 | 任意窗口 | 任意窗口 | 当前页面窗口 |
7、对数据结构有了解吗?给一个有序的数组,找某一个数是否存在。
8、输入一个网址到显示的总过程。
- 输入地址
- 浏览器查找域名的IP地址,这里包括:浏览器缓存、本机缓存、hosts文件、路由器缓存、DNS递归查询
- 打开一个socket与目标IP地址,端口建立TCP连接,三次握手如下:
i. 客户端发送一个TCP的SYN=1, seq=x的包到服务器
ii. 服务器发回一个SYN=1, ack=x+1,seq=y,ACK=1的包到客户端
iii. 客户端发送ack=y+1, seq=x+1,ACK=1 - TCP连接建立后发送HTTP请求
- 服务器接受请求并解析,把请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
- 服务器检查HTTP请求头是否包含缓存验证信息,如果验证缓存新鲜,返回304等对应状态码
- 处理程序读取完整请求并准备HTTP响应
- 服务器发送HTTP响应
- 浏览器接收响应,根据情况选择关闭TCP连接或保留重用,TCP的四次握手如下:
i. 主动方发送FIN=1, seq=u
ii. 被动方发送ACK=1,seq=v,ack=u+1
iii. 被动方发送FIN=1, ACK=1, seq=w,ack=u+1
iv. 主动方发送ACK=1,ack=w+1,seq=u+1 - 浏览器检查响应状态码
- 如果资源可缓存,进行缓存
- 对响应进行解码(如gzip压缩)
- 解析HTML文档,构建DOM树,下载资源,构造CSSOM树,执行js脚本。
其中,构建DOM树:
i. Tokenizing:根据HTML规范将字符流解析为标记
ii. Lexing:词法分析将标记转换为对象并定义属性和规则
iii. DOM construction:根据HTML标记关系将对象组成DOM树
构建CSSOM树:
i. Tokenizing:字符流转换为标记流
ii. Node:根据标记创建节点
iii. CSSOM:节点创建CSSOM树
根据DOM树和CSSOM树构建渲染树:
i. 从DOM树的根节点遍历所有可见节点,不可见节点包括:1)script,meta这样本身不可见的标签。2)被css隐藏的节点,如display: none
ii. 对每一个可见节点,找到恰当的CSSOM规则并应用
iii. 发布可视节点的内容和计算样式
js解析:
i. 浏览器创建Document对象并解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading
ii. HTML解析器遇到没有async和defer的script时,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用document.write()把文本插入到输入流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的文档内容
iii. 当解析器遇到设置了async属性的script时,开始下载脚本并继续解析文档。脚本会在它下载完成后尽快执行,但是解析器不会停下来等它下载。异步脚本禁止使用document.write(),它们可以访问自己script和之前的文档元素
iv. 当文档完成解析,document.readState变成interactive
v. 所有defer脚本会按照在文档出现的顺序执行,延迟脚本能访问完整文档树,禁止使用document.write()
vi. 浏览器在Document对象上触发DOMContentLoaded事件
vii. 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些内容完成载入并且所有异步脚本完成载入和执行,document.readState变为complete,window触发load事件
-
显示页面
9、说说对闭包的理解。
其实闭包也就是指有权访问另一个函数作用域的函数而已。常用的创建闭包的方法就是在函数内部创建另一个函数。
function F1 () {
var a = 100;
//返回一个函数,即函数作为返回值
//这里是这个函数的作用域
return function () {
//a是自由变量,要往【定义】的父级作用域中找
console.log(a);
}
}
var f1 = F1();
var a = 200; //全局作用域,与F1()中的毫无关系
f1(); // 100
1、函数作为返回值(上面)
2、函数作为参数传递(下面)
function F1 () {
var a = 100;
//返回一个函数,即函数作为返回值
//是这个函数的作用域
return function () {
//a是自由变量,要往【定义】的父级作用域中找
console.log(a);
}
}
var f1 = F1();
function F2 (fn) {
var a = 200;
fn();
}
F2(f1); // 100
***封装变量,收敛权限***
//隐藏数组,不用暴露出来,避免被修改
//封装存储10,20的数据源
function isFirstLoad () {
var _list = [];
return function (id) {
if (_list.indexOf(id) >= 0) {
return false;
} else {
_list.push(id); // _list自由变量,在父级作用域中找
return true;
}
}
}
//使用,在isFirstLoad函数外面,无法修改掉_list的值
var firstLoad = isFirstLoad();
console.log(firstLoad(10)); // true
console.log(firstLoad(10)); // false
console.log(firstLoad(20)); // true