# 浏览器对象详解
# 1、浏览器对象模型
参考资料:知识整理——浏览器对象模型 (opens new window)
BOM :Browser Object Model(浏览器对象模型),浏览器模型提供了独立于内容的、可以与浏览器窗口进行滑动的对象结构,就是浏览器提供的 API。其主要对象有:
- window对象:BOM 的核心,是 js 访问浏览器的接口,也是 ES 规定的 Global 对象
- location对象:提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属性,也是document的对象属性
- navigation 对象:获取浏览器的系统信息
- screen对象:用来表示浏览器窗口外部的显示器的信息等
- history对象:保存用户上网的历史信息
# 1、window对象
windows 对象是整个浏览器对象模型的核心,其扮演着既是接口又是全局对象的角色
- window 对象的属性和方法
alert(<msg>)/confirm(<msg>)/prompt(<msg>,<val>)
open(url,[target,string,boolean])
/*
url: 要加载的URL,
target: 窗口目标
string: 特定的字符串,以逗号分隔的字符串表示新窗口显示的特性
boolean: 表示新页面是否取代浏览器历史记录中当前加载页面的布尔值
*/
onerror() //多用于前端日志和错误采集
/* 事件处理程序,当未捕获的异常传播到调用栈上时就会调用它,并把错误消息输出到浏览器的 JavaScript 控制上。window.onerror(描述错误的一条消息, 字符串--存放引发错误的JavaScript代码所在的文档url, 文档中发生错误的行数) */
setTimeout(function(){}, val) //超时调用——在指定的时间过后执行代码
setInterval(function(){}, val)//间歇调用——每隔指定的时间就执行一次
/* 使用 `setInterval()` 方法的时候,再不加干涉的情况下,该方法会一直执行到页面的卸载,所以一般情况下`serInterval()`比较消耗性能。然后`setTimeout()`方法可以通过调用自身完成间歇调用的功能。所以说,在一般情况下使用`setTimeout()`来完成超时与间歇调用。*/
/* bug:app里嵌入H5时候,setInterval做的倒计时,10次递归 */
2
3
4
5
6
7
8
9
10
11
12
13
14
- 窗口位置
screenLeft //窗口相对于屏幕左边的位置,适用于IE、Safari、Chrome
screenTop
screenX //窗口相对于屏幕左边的位置,适用于IE、Safari、Chrome,适用于Firefox
screenY
moveBy(x,y) //全兼容
moveTo(x,y)
//跨浏览器获取窗口左边和上边位置
var leftPos = (typeof window.screenLeft == 'number') ? window.screenLeft : window.screenX
var topPos = (typeof window.screenTop == 'number') ? window.screenTop : window.screenY
2
3
4
5
6
7
8
9
10
- 窗口大小
innerWidth //可见视窗的大小
innerHeight
outerWidth //浏览器窗口本身的尺寸
outerHeight
resizeTo(width, height)
resizeBy(width, height)
/* 移动IE浏览器: 不支持该属性,当移动IE浏览器将布局视口的信息保存至document.body.clientWidth与document.body.clientHeight中*/
//获取浏览器视窗大小,可使用can i use网站查询
window.innerWidth || document.body.clientWidth
window.innerHeight || document.body.clientHeight
2
3
4
5
6
7
8
9
10
# 2、location对象
提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属性,也是 document 的对象属性
window.location === document.location //true
/* location 对象的主要属性
hash #host 返回url中的 hash(#后字符>=0)
host juejin.im:80 服务器名称+端口
hostname juejin.im 服务器名称
href 当前加载页面的完整的 url
pathname 返回url的的目录和(或)文件名 /book/5a7bfe595188257a7349b52a
port
protocol
search 返回url的查询字符串,以问号开头 ?name=aha&age=20
*/
2
3
4
5
6
7
8
9
10
11
location 的应用场景:
1、解析 url 查询字符串参数,并将其返回一个对象,可通过循环、正则来实现,方法有很多,实现的大体思路是:
通过location
的search
属性来获取当前 url 传递的参数,如果 url 中有查询字符串的话就将其问号截取掉,然后再遍历里面的字符串并以等号为断点,使用decodeURIComponent()
方法来解析其参数的具体数值,并将其放在对象容器中,并将其返回
2、载入新的文档,也可以说是刷新页面,主要有三个方法:
- assign(): location.assign("http://www.xxx.com")就可立即打开新 url 并在浏览器是我历史中生成一条新的记录, 在一个生成了 5 条浏览记录的页面中,然后使用 assign()跳转 url 后,history 记录只剩两条,一条是通过 assign 跳转的页面,另一条则是上一个页面(使用 assign()跳转方法的页面),其余的所有页面都被清除掉了
- replace(): location.replace("http://www.bbb.com")只接受 url 一个参数,通过跳转到的 url 界面不会在浏览器中生成历史记录,就是 history 的 length 不会+1,但是会替代掉当前的页面
- reload(): 其作用是重新加载当前显示的页面,当不传递参数的时候,如果页面自上次请求以来并没有改变过,页面就会从浏览器中重新加载,如果传递
true
,则会强制从服务器重新加载
# 3、navigation 对象
navigation 接口表示用户代理的状态和标识,允许脚本查询它和注册自己进行一些活动,navigation 应用场景:
- 检测插件
- 注册处理程序
navigator.onLine:浏览器是否链接了因特网
# 4、history对象
go()
back()
forword()
length //保存历史记录的数量,可用于检测当前页面是否是用户历史记录的第一页(history.length === 0)
2
3
4
# 5、screen对象
其提供有关窗口显示的大小和可用的颜色输入信息
window.screen.deviceXDPI/deviceYDPI 屏幕实际的水平DPI、垂直DPI
# 2、浏览器事件捕获和冒泡
浏览器事件模型中的过程主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段。
捕获->目标->冒泡
# 1、第三个参数
window.addEventListener('click', function(e){
console.log(e.target.nodeName) //指当前点击的元素
console.log(e.currentTarget.nodeName) //绑定监听事件的元素
}, false) //false为默认为冒泡,true为捕获
2
3
4
# 2、阻止事件传播
e.stopPropagation()
阻止冒泡和捕获阶段的传播。
stopImmediatePropagation() 如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法,则当前元素剩下的监听函数将不会被执行
# 3、阻止默认行为
e.preventDefault():可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为。
# 4、兼容性
- attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段
- addEventListener——兼容:firefox、chrome、IE、safari、opera;
# 5、面试题
1、页面为ul + li结构,点击每个li alert对应的索引
解析:浏览器获取元素方法
document.getElementById()
document.getElementsByTagName()
document.querySelector() //css选择符的模式匹配DOM元素,返回单个元素
document.querySelectorAll() //返回nodeList列表
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
</body>
<script type="text/javascript">
//第一种:给每个li绑定事件
const liList = document.getElementsByTagName("li");
for(let i = 0; i<liList.length; i++){
liList[i].addEventListener('click', function(e){
alert(`内容为${e.target.innerHTML}, 索引为${i}`);
})
}
//第二种:使用捕获绑定事件
const ul = document.querySelector("ul");
ul.addEventListener('click', function (e) {
const target = e.target;
if (target.tagName.toLowerCase() === "li") {
const liList = this.querySelectorAll("li");
index = Array.prototype.indexOf.call(liList, target); //数组和字符串位置函数indexOf
alert(`内容为${target.innerHTML}, 索引为${index}`);
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2、封装一个多浏览器兼容的绑定事件函数
class BomEvent {
constructor(element) {
this.element = element;
}
addEvent(type, handler) {
if (this.element.addEventListener) {
//事件类型、需要执行的函数、是否捕捉
this.element.addEventListener(type, handler, false);
} else if (this.element.attachEvent) {
this.element.attachEvent('on' + type, function () {
handler.call(element);
});
} else {
this.element['on' + type] = handler;
}
}
removeEvent(type, handler) {
if (this.element.removeEnentListener) {
this.element.removeEnentListener(type, handler, false);
} else if (element.datachEvent) {
this.element.detachEvent('on' + type, handler);
} else {
this.element['on' + type] = null;
}
}
}
// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation(ev) {
if (ev.stopPropagation) {
ev.stopPropagation(); // 标准w3c
} else {
ev.cancelBubble = true; // IE
}
}
// 取消事件的默认行为
function preventDefault(event) {
if (event.preventDefault) {
event.preventDefault(); // 标准w3c
} else {
event.returnValue = false; // IE
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 3、网络请求
# 1、XMLHTTPRequest对象
- 方法
- open(请求方法:“get/post”, 请求url, 是否异步(默认true))
- send(请求体发送数据,无则传入null)
- abort():收到响应之前取消异步请求
- setRequestHeader('MyHeader', 'MyValue')
- getResponseHeader('MyHeader')|getAllResponseHeader()
- 属性
- responseText
- responseXML
- status(响应HTTP状态)
- statusText(响应HTTP状态描述)
- readyState(响应状态,请求/响应过程的哪个阶段):0未初始化|1已打开|2已发送|3接收中|4完成,从一个值变为一个值,会触发readystatechange事件,readystatechange事件处理程序应该在调用open()之前赋值
- timeout超时时间,对应超时事件ontimeout
- 进度事件:loadstart、progress事件:接收数据时反复触发、error、abort、load、loadend
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');
// request state change event
xhr.onreadystatechange = function () {
// request completed?
if (xhr.readyState !== 4) return;
if (xhr.status === 200) {
// request successful - show response
console.log(xhr.responseText);
} else {
// request error
console.log('HTTP error', xhr.status, xhr.statusText);
}
};
xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
// progress事件可以报告长时间运行的文件上传
xhr.upload.onprogress = p => {
console.log(Math.round((p.loaded / p.total) * 100) + '%');
}
// start request
xhr.send(null);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 2、fetch
方法:fetch(url,{}init对象),返回Promise对象,只支持异步
响应通过response对象获取:fetch().then((response)=>{}).catch(()=>{}),response对象混入了body,提供了5个方法,将ReadableStream转存到缓冲区的内存里,将缓冲区转换为js对象,通过Promise返回。
response.text() //转为text
response.json() //转为json
response.formData()
response.arrayBuffer()
response.blob()
错误不会reject:当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject
不支持超时设置
需要借用AbortController终止fetch
fetch(
'http://domain/service', {
method: 'GET'
}
)
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.error('error:', error));
//credentials:omit不发送cookie|same-origin同源发送cookie(默认)|include都发送cookie
fetch(
'http://domain/service', {
method: 'GET',
credentials: 'same-origin'
}
)
// 错误不会reject
// HTTP错误(例如404 Page Not Found 或 500 Internal Server Error)不会导致Fetch返回的Promise标记为reject;.catch()也不会被执行。
// 想要精确的判断 fetch是否成功,需要包含 promise resolved 的情况,此时再判断 response.ok是不是为 true
fetch(
'http://domain/service', {
method: 'GET'
}
)
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
})
.then(json => console.log(json))
.catch(error => console.error('error:', error));
// 不支持直接设置超时, 可以用promise
function fetchTimeout(url, init, timeout = 3000) {
return new Promise((resolve, reject) => {
fetch(url, init)
.then(resolve)
.catch(reject);
setTimeout(reject, timeout);
})
}
// 中止fetch
// signal用于支持AbortController中断请求
const controller = new AbortController();
//AbortController接口表示一个控制器对象,允许你根据需要中止一个或多个 Web请求。
fetch(
'http://domain/service', {
method: 'GET',
signal: controller.signal
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.error('Error:', error));
controller.abort();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 3、HTTP状态码和首部
# 1、HTTP状态码
100信息性|200成功|300重定向|400客户端错误|500服务器错误
- 200 get 成功
- 201 post 成功
- 301 永久重定向
- 302 临时重定向
- 307 临时重定向,使用get请求重定向
- 304 协商缓存 服务器文件未修改
- 400 客户端请求有语法错误,不能被服务器识别
- 403 服务器受到请求,但是拒绝提供服务,可能是跨域
- 404 请求的资源不存在
- 405 请求的method不允许
- 500 服务器发生不可预期的错误
# 2、HTTP首部
通用首部:Connection、Date、MIME-Version、Cache-Control
请求首部:User-Agent、Accept(MIME类型)、Accept-Encoding、Cookie
响应首部:Set-Cookie
实体首部:Content-Length、Content-Type、ETag、Expires、Last-Modified
# 3、body格式
- form-data:就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来说明文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
- x-www-form-urlencoded:就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23
- raw:可以上传任意格式的文本,可以上传text、json、xml、html等
- binary:Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。
# 4、封装Ajax请求
interface IOptions {
url: string;
type?: string;
data: any;
timeout?: number;
}
function formatUrl(json) {
let dataArr = [];
json.t = Math.random();
for (let key in json) {
dataArr.push(`${key}=${encodeURIComponent(json[key])}`)
}
return dataArr.join('&');
}
export function ajax(options: IOptions) {
return new Promise((resolve, reject) => {
if (!options.url) return;
options.type = options.type || 'GET';
options.data = options.data || {};
options.timeout = options.timeout || 10000;
let dataToUrlstr = formatUrl(options.data);
let timer;
// 1.创建
let xhr;
if ((window as any).XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
if (options.type.toUpperCase() === 'GET') {
// 2.连接
xhr.open('get', `${options.url}?${dataToUrlstr}`, true);
// 3.发送
xhr.send();
} else if (options.type.toUpperCase() === 'POST') {
// 2.连接
xhr.open('post', options.url, true);
xhr.setRequestHeader('ContentType', 'application/x-www-form-urlencoded');
// 3.发送
xhr.send(options.data);
}
// 4.接收
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
clearTimeout(timer);
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
}
}
if (options.timeout) {
timer = setTimeout(() => {
xhr.abort();
reject('超时');
}, options.timeout)
}
// xhr.timeout = options.timeout;
// xhr.ontimeout = () => {
// reject('超时');
// }
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 5、axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中,有以下特点:
- 从浏览器中创建 XMLHttpRequests (opens new window)
- 从 node.js 创建 http (opens new window) 请求
- 支持 Promise (opens new window) API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF (opens new window)
# 1、常见方法
//全局请求
//1、get请求
axios.get('./user?id=1234').then(function(response){}).catch(function(error){})
axios.get('./user',{params:{id: 1234}}).then(function(response){}).catch(function(error){})
//2、post请求
axios.post('/user',{id: 1234}).then(function(response){}).catch(function(error){})
//实例请求
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
instance#request(config)
instance#get(url[, config])
instance#post(url[, data[, config]])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 2、相关配置
在 lib/defaults.js
找到的库的默认值,然后是实例的 defaults
属性,最后是请求的 config
参数。后者将优先于前者。
- 全局配置
- 实例配置
- 请求的config参数
//全局配置
axios.defaults.baseURL = 'https://api.example.com';
//实例配置
var instance = axios.create();
instance.defaults.timeout = 2500;
//请求参数
instance.get('/longRequest', {
timeout: 5000
});
2
3
4
5
6
7
8
9
10
11
# 1、请求配置
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // default
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `params` 是即将与请求一起发送的 URL 参数,get
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `data` 是作为请求主体被发送的数据,post
data: {
firstName: 'Fred'
},
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // default
// `responseEncoding` indicates encoding to use for decoding responses
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // default
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// `cancelToken` 指定用于取消请求的 cancel token
cancelToken: new CancelToken(function (cancel) {
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 2、响应结构
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {},
// 'request'
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance the browser
request: {}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意:默认情况下,axios将JavaScript对象序列化为JSON。 要以application / x-www-form-urlencoded格式发送数据,需做处理。
- 使用使用URLSearchParams API
- 使用qs库编码数据
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3、错误处理
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 3、取消发送
使用 cancel token 取消请求
- 使用
CancelToken.source
工厂方法创建 cancel token - 传递一个 executor 函数到
CancelToken
的构造函数来创建 cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// cancel the request
cancel();
2
3
4
5
6
7
8
9
10
11
12
# 4、并发处理
axios.all(iterable)
axios.spread(callback)
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
//acct方法1返回值
//perms方法2的返回值
}));
2
3
4
5
6
7
8
9
10
11
12
13
14