Javascript 异步操作(Promise)

2020/7/10 JavaScript

# Javascript异步操作

# 一、Javascript 执行程序过程

       JS执行过程是单线程的,单线程就是所有程序只运行在一条线程上。就好像所有操作都必须在一条流水线上工作,可能某一个操作较为复杂,就容易阻塞后面的操作。JS是单一服务的。

# 二、解决方法

  • 回调函数        当这个任务完成后,调用下一个任务的函数。异步有多深,嵌套就越深,代码复杂。
  • Promise对象        异步任务成功,调用resolve方法将状态变成Fulfilled(完成)。任务失败,调用reject方法将状态变成Rejected(失败),通过使用链式调用的方式。。
  • async/await语法        它让异步代码能够像同步代码一样从上到下执行。

# 三、回调函数

  • 案例一:俩个流水线之间
 setTimeout((res)=>{//等待一秒后执行
       console.log('完成流水一')
     },1000)
       console.log('完成流水二')
   }
1
2
3
4
5

在这里插入图片描述        从结果中可以看出JS先执行任务二,在执行任务一。当JS执行编译任务一时,知道是一秒后在执行,会将该任务放在任务堆里等待时间到后在执行该任务。这段时间就先执行任务二。


  • 案例二:单个流水线多个任务(回调函数)
setTimeout((res)=>{
       console.log('完成操作一')
       setTimeout((res)=>{
        console.log('完成操作二')
        console.log('流水线工作完成')
       },2000)
     },1000)
1
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)
     }
1
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)
    })
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

任务成功 任务失败(把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)
     })
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

在这里插入图片描述        根据时间(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)
    }
1
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)
    },
1
2
3
4
5
6
7
8
9
10
11

在这里插入图片描述

# 六、总结

       这三种方法都有各自的特点,但第一种方法基本很少使用。基本上都是使用第二、三种方法。