Javascript 异步操作(Promise)
# Javascript异步操作
# 一、Javascript 执行程序过程
JS执行过程是单线程的,单线程就是所有程序只运行在一条线程上。就好像所有操作都必须在一条流水线上工作,可能某一个操作较为复杂,就容易阻塞后面的操作。JS是单一服务的。
# 二、解决方法
- 回调函数 当这个任务完成后,调用下一个任务的函数。异步有多深,嵌套就越深,代码复杂。
- Promise对象 异步任务成功,调用resolve方法将状态变成Fulfilled(完成)。任务失败,调用reject方法将状态变成Rejected(失败),通过使用链式调用的方式。。
- async/await语法 它让异步代码能够像同步代码一样从上到下执行。
# 三、回调函数
- 案例一:俩个流水线之间
setTimeout((res)=>{//等待一秒后执行
console.log('完成流水一')
},1000)
console.log('完成流水二')
}
2
3
4
5
从结果中可以看出JS先执行任务二,在执行任务一。当JS执行编译任务一时,知道是一秒后在执行,会将该任务放在任务堆里等待时间到后在执行该任务。这段时间就先执行任务二。
- 案例二:单个流水线多个任务(回调函数)
setTimeout((res)=>{
console.log('完成操作一')
setTimeout((res)=>{
console.log('完成操作二')
console.log('流水线工作完成')
},2000)
},1000)
2
3
4
5
6
7
缺点是:如果流水线的任务多,嵌套就越深。
# 四、Promise 对象
- 案例一:一个任务多个操作步骤
new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('完成操作一')
// 成功后调用resolve方法
resolve()//进入then()方法
},1000)
}).then((res)=>{
setTimeout(()=>{
console.log('完成操作二')
console.log('任务完成')
},2000)
}
2
3
4
5
6
7
8
9
10
11
12
- 案例二:多个任务执行,判断是否已经都完成了
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p1')
//失败
//reject('失败任务为p1')
//成功
resolve('成功完成任务p1')
}, 2000)
})
//任务2
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p2')
resolve('成功完成任务p2')
}, 1000)
})
//任务3
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p3')
resolve('成功完成任务p3')
}, 3000)
})
// 判断三个任务是否已经完成
Promise.all([p1, p2, p3]).then((res)=>{
console.log('任务全部完成')
console.log(res)
}).catch((err)=>{
console.log('有一个或多个任务失败')
console.log(err)
})
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
任务成功 任务失败(把reject()取消注释,resolve()进行注释) 第一张图:因为任务p2是过一秒后执行,p1是过俩秒后执行,故p2先输出。 第二张图:执行任务p1失败,调用reject方法,方法中的参数传递到Promise.all方法中的catch()的err,将其输出。但其他任务没有受到影响,继续执行。
适用范围:比如:你需要上传多张照片到数据库里,多张照片就好比多个任务,你必须保证多张照片全部上传成功后才能执行接下来的任务,至于相片的先后顺序,我们并不关心。
- 案例三:多个任务判断谁最先完成
//任务1
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p1')
//失败
reject('失败任务为p1')
//成功
resolve('成功完成任务p1')
}, 2000)
})
//任务2
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p2')
resolve('成功完成任务p2')
}, 1000)
})
//任务3
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务p3')
resolve('成功完成任务p3')
}, 3000)
})
//竞赛
Promise.race([p1, p2, p3]).then((res)=>{
console.log('有一个任务完成')
console.log(res)
}).catch((err)=>{
console.log('任务失败')
console.log(err)
})
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
根据时间(p1:2s ,p2:1s,p3:3s),所以任务一先执行完成,触发函数Promise.race()方法。其他任务进行执行。
适用范围:比如当有一个需要向服务器发送请求时,可以设置任务一为发送请求,任务二可以设置成2秒,执行其他操作。如果向执行任务一则说明请求成功,如果任务二先执行,则说明请求超时(2秒),失败。
# 五、async/await 语法(koa2原生语法)
(1)没有使用async/await时
this.demo();
demo (){
console.log('1')
this.demo1()//输出2
console.log(3)
},
demo1(){
setTimeout((res)=>{
console.log(2)
},3000)
}
2
3
4
5
6
7
8
9
10
11
可以看出,是异步处理
(2)使用async/await时
async demo (){//async 异步
console.log('1')
await this.demo1()
//await 相当于等待了3秒后在执行下一步操作
console.log(3)
},
demo1(){
setTimeout((res)=>{
console.log(2)
},3000)
},
2
3
4
5
6
7
8
9
10
11
# 六、总结
这三种方法都有各自的特点,但第一种方法基本很少使用。基本上都是使用第二、三种方法。