前言

本文主要记录博主遇到的JavaScrprt的补充知识。


Ajax

参考:3小时Ajax入门到精通 CSDN

AJAX 简介

​ 异步的 JS 和 XML(AsynchronousJavaScript And XML),浏览通过 Ajax 向服务器发送异步请求,可以无刷新获取数据。

  • 优点:无需刷新页面与服务器端进行通信、允许你根据用户事件来更新部分页面内容
  • 缺点:没有浏览历史不能回退、存在跨域问题、SEO 不友好

XML 简介

​ 可扩展标记语言,和 HTML 类似,但 XML 中没有预定义标签,用来表示一些数据

1
2
3
4
5
6
7
8
<!-- 使用 XML 来表示 一个学生的信息 -->
<student>
<name>张三</name>
<age>18</age>
<gender></gender>
</student>
<!-- XML 已被 JSON 取代 -->
{"name":"孙悟空","age":18,"gender":"男"}

HTTP相关问题 MDN文档

  • 请求报文

    1. 请求行:请求类型(method–get、post) 请求路径(url)、HTTP版本协议(HTTP1.1、HTTP2.0)
    2. 请求头: 格式(key:value),如:Content-type: application/x-www-form-urlencoded
    3. 请求空行:必须要有
    4. 请求体:get请求体为空、post可有可无
  • 响应报文

    1. 响应行:HTTP版本协议(HTTP1.1、HTTP2.0)、响应状态码(200)、响应状态字符串(ok)
    2. 响应头: 格式(key:value),如:Content-type: text/html;charset=utf-8
    3. 响应空行:必须要有
    4. 响应体:响应主要内容

原生 Ajax 使用

1
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
/** 发送请求4个步骤 */
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open('Get', 'http://localhost:3333')
// 3.发送
xhr.send();
// 4.事件绑定响应
xhr.onreadystatechange = () => {
// readyState 是 xhr对象中的属性, 表示状态 0 1 2 3 4
// 0 -> 创建对象
// 1 -> 初始化
// 2 -> 发送
// 3 -> 服务器返回结果中
// 4 -> 服务器返回了所有的结果
if (xhr.readyState === 4 && xhr.status == 200) {
console.log(xhr.response) // 响应体
console.log(xhr.status) // 响应状态码
console.log(xhr.statusText) // 响应字符串
console.log(xhr.getResponseHeader('Content-type')) // 获取指定名称的响应头
console.log(xhr.getAllResponseHeaders) // 所有的响应头
}
}

// 携带请求参数
xhr.open('Get', 'http://localhost:3333?a=100&b=200')

// post 请求设置请求体
xhr.send('a=100&b=200') // 里面的格式可自定义(一般x-www-form-urlencoded或者json)
// 设置请求头,在opne后面调用方法
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
xhr.setRequestHeader('token','xxx') // 设置多个(再写一个即可)

// 对响应 JSON 数据的处理
// 1.手动转化
JSON.parse(xhr.response)
// 2.自动转化
// 设置响应头数据类型
xhr.responseType = 'json'

// 了解ie浏览器Ajax请求缓存问题,同一个请求url不变走缓存,加一个参数保证每次不一样即可
xhr.open('Get', 'http://localhost:3333?t='+Date.now) // 实际情况不需要自己加,工具会自动处理

// Ajax 请求超时与网络异常,(写open上面比较好,其他位置也不影响)
// 超时设置 (2秒)
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function(){
alert('网络超时,请稍后重试')
}
// 网络异常回调
xhr.onerror = function(){
alert('网络异常,请稍后重试')
}
// 手动取消请求
xhr.abort()

JQuery Ajax 使用

1
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
// 发送 get post 请求
// 接收四个参数:
// 1.url 请求 HTML 页面的 URL 地址
// 2.data(可选) 发送至服务器的 key/value 数据
// 3.callback(可选) 回调函数,只有当请求成功才执行!
// 4.type(可选) 服务器返回的数据格式,包括 xml/html/json/text 等
$.get('http://localhost:8000/jquery-server', {}, function(data){
console.log(data)
}, 'json')

$.post('http://localhost:8000/jquery-server', {a:100, b:200}, function(data){
console.log(data)
}, 'json')

// Ajax 通用
$.ajax({
type: 'GET', // 请求方法
url: 'http://localhost:8000/jquery-server', // 请求地址
data: {}, // 携带参数
dataType: 'json', // 响应体类型设置
timeout: 3000, // 超时时间
headers: { // 请求头信息
token: 'xxx'
},
success: function(res) { // 成功后执行的回调
console.log(res)
},
error: function(e) { // 失败时执行的回调,(超时也会走这个)
console.log(e)
},
complete: function(data) { // 请求完成后调用的回调 (无论是否成功)
console.log(data)
}
})

axios 使用

文档:axios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// get post 请求(注意:delete 与 get 一样没有请求体 )
axios.get('http://localhost:8000/axios-server', {
params: { //url参数
id: 1
},
headers:{ //请求头信息
name:'xxx'
}
}).then()

axios.post('http://localhost:8000/axios-server',
{ // data 请求体
a: 10
},
{ // config 配置
params: { //url参数
id: 1
},
headers:{ //请求头信息
name:'xxx'
}
}).then()

// axios 写法
axios({...}).then()

fetch 语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fetch('http://localhost:8000/fetch-server',{
//请求方法
method:'POST',
//请求头
headers:{
name:'hanser'
},
//请求体
body: 'name=admin&pd=admin'
}).then(Response=>{
console.log(Response)
return Response.text() // 或者使用 Response.json()
}).then(Response=>{
console.log(Response)
})

jsonp 的使用

JSONP(JSON with Padding),是一个非官方的跨域解决方案,只支持get 请求。

1
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
// 原理: script 标签的src 属性来发送请求,返回一个函数的调用的js代码,不能直接返回数据(浏览器不认识)。
// 不是 XMLHttpRequest 和 fetch 请求

// 原生jsonp使用
function handle(data) { // 准备一个handle的回调函数
console.log(data)
}
// 1 创建 script 标签发送请求
const script = document.createElement('script')
//2 设置标签的src属性
script.src = 'http://localhost:8000/check-username'
//3 将script插入文档中
document.body.appendChild(script)

// 后端返回的是一个 js 代码(调用 handle 函数)
app.all("/articles", (req, res) => {
let data = JSON.stringify({name:'xxx'})
res.send(`handle(${data})`);
});


// JQuery 的 jsonp 使用
// 1.使用 getJSON 方法,必须携带callback参数(固定写法),后端可以req接收这个函数名
$.getJSON('xxx?callback=?', function(data) {
console.log(data)
})
// 2.使用 ajax 写法:见前端知识记录中的记录

补充跨域CORS:就是服务端设置请求头,来允许哪些可以访问资源,还有是否支持自定义请求头、请求响应方法等。

资料:CORS


Promise 补充

参考:尚硅谷Web前端Promise教程从入门到精通

Promise api

1
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
/** Promise.resolve() */
let p1 = Promise.resolve(521);
//如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
//如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('OK');
reject('Error');
}));
// console.log(p2);
p2.catch(reason => {
console.log(reason);
})


/** Promise.reject() */
// 返回一个失败的 promise 对象
let p = Promise.reject(521);
let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
resolve('OK');
}));
// 都是失败的

/** Promise.all 方法 */
// 返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
let p1 = new Promise((resolve, reject) => {
resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');

const result = Promise.all([p1, p2, p3]);
console.log(result);

/** Promise.race方法 */
// 返回一个新的 promise,第一个完成的 promise 的结果状态就是最终的结果状态
const pRace = Promise.race([p1, p2, p3])
// 谁先完成就输出谁(不管是成功还是失败)
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');


const result = Promise.race([p1, p2, p3]);

console.log(result);

Promise 的几个问题

1.如何改变 promise 的状态?

1
2
3
4
5
6
7
8
9
10
const p = new Promise((resolve, reject) => {
//resolve(1) // promise变为resolved成功状态
//reject(2) // promise变为rejected失败状态
throw new Error('出错了') // 抛出异常,promise变为rejected失败状态,reason为抛出的error
})
p.then(
value => {},
reason => {console.log('reason',reason)}
)
// reason Error:出错了

2.一个 promise 指定多个成功/失败回调函数,都会调用吗?

​ 当 promise 改变为对应状态时都会调用

3.改变 Promise 状态和指定回调函数谁先谁后?

  • 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  • 如何先改状态再指定回调?

​ 在执行器中直接调用 resolve()/reject()

​ 延迟更长时间才调用 then()

  • 什么时候才能得到数据?

​ 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据

​ 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.Promise then方法的返回结果特点

​ 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果

​ 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值

​ 如果抛出异常,新promise变为rejected,reason为抛出的异常

5.异常穿透

​ 当使用 Promise 的 then 链式调用时, 可以在最后指定失败的回调

​ 前面任何操作出了异常, 都会传到最后失败的回调中处理

6.中断 promise 链

​ 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数,办法:在回调函数中返回一个pending状态的promise对象


补充 axios.all 使用

1
2
3
4
5
6
7
8
9
10
11
12
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) {
// 两个请求现在都执行完成
}));