0%

Promise 异步

js核心代码在执行过程中,有的代码 代码 会在跳过执行,等待一段时间以后 又会继续执行,打破了从上至下,从左至右的执行顺序, 这种代码我们统称为异步代码

  • 定时器 延时器
  • ajax
  • 事件的监听和执行函数
  • Promise 异步 类

1.基础语法

promise状态:

pending 等待

resolve=== fulfilled 成功

reject rejected 失败

promise 状态只会有一个结果, 状态不可逆, 等待--->成功 等待-->失败

1
2
3
4
5
6
7
8
9
10
11
12
//创建pormise实例对象
let p1 = new Promise(function(resolve,reject){
// resolve:等待一段时间后 成功执行之后的回调函数
// reject: 等待一段时间后 失败执行之后的回调函数
//如果promise 的状态 是不成功 不失败 pending 等待....
resolve() //只要调用了resolve 就表示状态改为成功fulfilled
reject() //只要调用了reject 状态就表示 失败rejected
})




2.promise 解决的问题

回调地狱问题

回调函数 有 回调 里面 还有回调

回调函数嵌套 层级 超过三层,一般就说形成了回调地狱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

const http = {
get(url,callback){
let xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
callback(JSON.parse(xhr.responseText))
}
}
},
post(url,data,callback){
let xhr = new XMLHttpRequest();
xhr.open('post',url);
xhr.setReqeustHeader('content-type','application/json')
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
callback(JSON.parse(xhr.responseText))
}
}
},
}

3.通过ajax 体验回调地狱 11:15

http.js 实现

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
  
<div class="list">

</div>

<script src="./http.js"></script>
<script>
let listDom = document.querySelector('.list')
let data = [];
// 请求用户的列表
http.get('/list',(res)=>{

data= res.data
//循环数组 拿到id 请求对应的username 更新到data里面

for(let i=0;i<data.length;i++){
http.post('/info',{id:data[i].id},(res1)=>{
data[i].username = res1.data.username
//请求头像
let formData = {id:data[i].id,username: data[i].username}
http.post('/avatar',formData,(res2)=>{
data[i].avatar = res2.data.avatar;

//将最新数据 拼接dom输出到页面
listDom.innerHTML+=`
<div class="item">
<div class="img">
<img src="${data[i].avatar}" alt="">
</div>
<div class="info">
<div class="id">
用户编号:${data[i].id}
</div>
<div class="name">
用户名字:${data[i].username}
</div>
</div>
</div>
`;
})

})
}
})
</script>

3.回调地狱

多个回调函数的嵌套,超过3级 形成回调地狱 【代码的可读性极低】

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
http.get('/list',(res)=>{
data= res.data
//循环数组 拿到id 请求对应的username 更新到data里面
for(let i=0;i<data.length;i++){
http.post('/info',{id:data[i].id},(res1)=>{
data[i].username = res1.data.username
//请求头像
let formData = {id:data[i].id,username: res1.data.username}
http.post('/avatar',formData,(res2)=>{
data[i].avatar = res2.data.avatar;

//将最新数据 拼接dom输出到页面
listDom.innerHTML+=`
<div class="item">
<div class="img">
<img src="${data[i].avatar}" alt="">
</div>
<div class="info">
<div class="id">
用户编号:${data[i].id}
</div>
<div class="name">
用户名字:${data[i].username}
</div>
</div>
</div>
`;
})
})
}
})

3.promise 解决回调地狱问题

三个:

pending 等待

fufailled resolve 成功

rejected reject 失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1s 之后 通过promise 返回  这个数字   默认pending
// 偶数:是偶数 promise 成功状态
// 奇数:是奇数 promise 失败状态
let num =100
new Promise(function(resolve,reject){
setTimeout(()=>{
if(num%2 ==0){
resolve('是偶数')
}else{
reject('是奇数')
}
},1000)
}).then(function(res){
console.log(res);
}).catch(function(err){
console.log(err);
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//1s 之后 通过promise 返回  这个数字   默认pending
// 偶数:是偶数 promise 成功状态
// 奇数:是奇数 promise 失败状态
let num =101
let p = new Promise(function(resolve,reject){
setTimeout(()=>{
if(num%2 ==0){
resolve('是偶数')
}else{
reject('是奇数')
}
},1000)
})

//成功后自动执行then 调用了resolve 自动走 then
p.then(function(res){
console.log(res);
})

//失败后自动执行catch 调用了reject 自动走 catch
p.catch(function(err){
console.log(err);

})

4.promise 的then 的链式调用

promise 的 then链式调用 可以解决ajax 的回调地狱

1
2
p.then(res=>{}).then(res1=>{}).then(res2=>{})
//链式then的调用共计3次 ===> 一共调用了 三次 reslove ===> 三个promise
  • ajax 请求的三次接口
1
2
3
4
5
6
7
8
9
10
11
let data = {};
http.get('/list',res=>{
data = res.data;
http.post('/info',{id:res.data.id},res1=>{
http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{
data.username = res2.data.username;
data.avatar = res2.data.avatar;
console.log(data);
})
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
new Promise((resolve,reject)=>{
http.get('/list',res=>{
data = res.data;
resolve(res)
})
}).then(res=>{
return new Promise((resolve,reject)=>{
http.post('/info',{id:res.data.id},res1=>{
resolve(res1)
})
})
}).then(res1=>{
return new Promise((resolve,reject)=>{
http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{
resolve(res2)
})
})
}).then(res2=>{
console.log(res2);
data.avatar = res2.data.avatar;
data.username = res2.data.username
})

5.简化代码 ,提炼公共部分代码 形成代码的封装

复写axios.js

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
const base_url = 'http://8.137.157.16:9004'
const http = {
get(url){
let p = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('get',base_url+url);
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
return p;
},
post(url,data){
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('post',base_url+url);
xhr.setRequestHeader('content-type','application/json')
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
},
}
window.http = http;
1
2
3
4
5
6
7
8
http.get('/list')
.then(res => {
return http.post('/info', { id: res.data.id })
}).then(res1 => {
return http.post('/avatar', { id: res1.data.id, username: res1.data.username })
}).then(res2 => {
console.log(res2);
})

6.axios 的使用与原理

promise+ajax(XMLHttpReqeust)

  • 找axios的中文网
  • 下载axios.js bootcdn 下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 <script src="./axios.js"></script>
<script>
let data = {};

// 统一服务器地址
axios.defaults.baseURL = 'http://8.137.157.16:9004';

axios.get('/list')
.then(res => {
console.log(res);
return axios.post('/info', { id: res.data.data.id })
}).then(res1 => {
return axios.post('/avatar', { id: res1.data.data.id, username: res1.data.data.username })
}).then(res2 => {
console.log(res2.data);
})

  • http.js 封装
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
let base_url = 'http://8.137.157.16:9004'
const http = (obj)=>{
let {method,url,data,responseType} = obj;
if(method=='get'){
return http.get(url)
}
if(method=='post'){
let type = responseType==0?'application/json':'application/x-www-form-urlencoded'
return http.post(url,data,type)
}
}
http.get = (url)=>{
let p = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();

xhr.open('get',base_url+url);
xhr.send()
xhr.onreadystatechange = function(){

if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
return p;
}
http.post = (url,data,responseType='application/json')=>{
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('post',base_url+url);
xhr.setRequestHeader('content-type',responseType)
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
}
window.http = http;

7. 浏览器事件循环机制 event loop

同步 异步的深入研究

代码执行顺序

定时器 延时器

ajax 事件

promise

1.promise 是异步吗?

promise 本身不是异步, promise.then 方法是异步

2.同步和 异步问题

先执行所有的同步 再 执行异步

3.浏览器事件循环机制

代码执行顺序:

遵循 从上至下 从左至右 依次执行。

异步代码: 宏任务(定时器 延时器 ajax 事件) 微任务 promise.then

如果微任务和 宏任务在同一个异步层级,先执行 所有的微任务 再执行宏任务

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
console.log(1);



new Promise((resolve,reject)=>{
console.log(3);

console.log(5);
resolve()
}).then(_=>{
setTimeout(()=>{
console.log(4);
},0)
console.log(6);

})
console.log(7);


setTimeout(()=>{
console.log(2);

},0)

// 1 3 5 7 6 2 4

面试题:

1.你对回调地狱的理解?

2.如何解决回调地狱?

3.event loop 浏览器事件循环机制 (关于同步异步代码的执行顺序)?

4.promise 是异步还是同步?

5.宏任务和微任务的区别 分别有哪些?

async await promise 内置方法 all race