前端开发-关于异步编程

异步编程

  本篇主要介绍关于js异步编程的知识点,包括总结promise的基本用法,手写一个自定义的promise以及ES8加入的async和await语法。

 

1.promise的概念

  首先promise是服务异步编程而在ES6中加入的新特性,本质也是一个对象。(这里的异步操作一般为io操作,一般有三类:文件读取、网络请求和数据库读取)

  实例化一个promise对象,promise接收一个函数,函数中又含有两个参数,注意这两个参数也是函数类型,在异步操作完成后根据返回结果来判断执行resolve还是reject,resolve和reject既可以保存异步操作后的结果,也会改变promise的状态,promise的状态有三种(padding待定,fulfilled成功和rejected失败),其中resolve会将状态改为fulfilled,而reject会将状态改为rejected。

const p = new Promise((resolve,reject) => {
    // 这里做异步操作
    if(!err){
        resolve();
    }else{
        reject(); 
    }
})    

 

2.promise.then()方法

  介绍完promise的概念后,我们来介绍promise的核心方法then(),then方法中接受两个回调函数,与promise的成功和失败两个状态相对应,且根据状态来执行相应的方法。

  

1 p.then(
2  res=>{
3        console.log(res)     
4     } 
5   reason=>{
6         console.log(reason)
7     }       
8 )        

 

3.promise读取多文件的实例

 1 // 需求:异步读取三个文件的内容并打印下来
 2 const fs = require('fs')
 3 
 4 const p = new Promise((resolve, reject)=>{
 5   fs.readFile('./resource/1.md',(err,data)=>{
 6     if(err) reject(err) // 若出现错误用reject接收错误
 7     resolve(data) // 若成功用resolve保存data数据
 8   })
 9 })
10 p.then(res=>{ // 这里的res是resolve(data)存储的data数据
11   // 注意这里返回的是一个promise对象,以为我们根据promise的状态去判断文件是否读取成功,而读取结果是通过resolve来保存
12   return new Promise((resolve, reject)=>{
13     fs.readFile('./resource/2.md',(err,data)=>{
14       if(err) reject(err) 
15       resolve([res,data]) // 这里目的是将读取结果封装成一个数组,再有resolve来保存这个数组
16     })
17   })
18 }).then(res=>{ // 此时的res为[res,data]
19   return new Promise((resolve, reject)=>{
20     fs.readFile('./resource/3.md',(err,data)=>{
21       if(err) reject(err) 
22       const result = res.push(data) // 向数组中传入第三个文件的数据
23       resolve(result) 
24     })
25   })
26 }).then(
27   res=>{
28     console.log(res.join('\r\n')) // 文件全部读取完毕,直接打印,没有要执行的异步操作了,不用再封装promise对象
29   }
30 )

 

4.手写一个Promise

 1 class Commitment {
 2   // 定义手写Promise的三种状态,这里使用类的静态属性static
 3   static PENDING = '0';
 4   static FULFILLED = '1';
 5   static REJECTED = '2';
 6 
 7   // 构造器写入传入的方法,该方法的两个参数也是方法,需要用普通方法定义
 8   constructor(func) {
 9     this.status = Commitment.PENDING;
10     this.result = null; // 给对应状态赋相应的返回值
11     // 创建数组保存resolve和reject函数
12     this.resolveCallbacks = [];
13     this.rejectCallbacks = [];
14     // 捕获错误
15     try {
16       func(this.resolve.bind(this),this.reject.bind(this)); // 这里需要bind绑定this
17     } catch (error) {
18       this.reject(error); // 将错误通过reject抛出
19     }
20     
21   }
22 
23   // resolve和reject是在事件循环末尾执行的,所以用setTimeout
24   // 成功是调用的方法
25   resolve(result) {
26     setTimeout(()=>{
27       if (this.status === Commitment.PENDING) {
28         this.status = Commitment.FULFILLED;
29         this.result = result;
30         // 成功时调用成功方法数组中的回调方法
31         this.resolveCallbacks.forEach(callback=>{
32           callback(result)
33         });
34       }
35     });
36   }
37 
38 
39   // 失败时调用的方法
40   reject(result) {
41     setTimeout(()=>{
42       if (this.status === Commitment.PENDING) {
43         this.status = Commitment.REJECTED;
44         this.result = result;
45         // 失败时调用失败方法数组中的回调方法
46         this.rejectCallbacks.forEach(callback=>{
47           callback(result)
48         });
49       }
50     });
51   }
52 
53   // then方法
54   then(onFulFILLED,onREJECTED) {
55     // 实现promisethen方法的链式调用,我们就需要在then方法中返回promise实例
56     return new Commitment((resolve, reject)=>{
57     // 对then方法参数做预先判断,若不为函数类型则置为空函数
58     onFulFILLED = typeof onFulFILLED === 'function' ? onFulFILLED : () => {};
59     onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => {};
60     // 待定时将还未运行的参数方法压入对应的状态的方法数组
61     if (this.status === Commitment.PENDING) {
62       this.resolveCallbacks.push(onFulFILLED);
63       this.rejectCallbacks.push(onREJECTED);
64     }
65     if (this.status === Commitment.FULFILLED) {
66       // 添加异步执行,用setTimeout
67       setTimeout(()=>{
68         onFulFILLED(this.result);
69       });    
70     }
71     if (this.status === Commitment.REJECTED) {
72       setTimeout(()=>{
73         onREJECTED(this.result);
74       }); 
75     }
76     });
77   }
78 }

 

5.async和await

  async和await的实现基础是promise对象,async可以标识一个函数作为异步函数,await只能存在async所表识的异步函数函数中,它们出现的意义是将异步代码书写起来和同步代码是一样的。另外,await后面只能跟promise对象。

  用async+await重写一下上面的需求就是这样的:

 1 // 首先定义三个读取方法,读取1.md,2.md和3.md
 2 
 3 const fs = reqiure('fs')
 4 // 这里我们的方法要返回一个Promise对象,方便后面使用
 5 function readM1() {
 6   return new Promise((resolve,reject)=>{
 7     fs.readFile('./resource/1.md', (err,data)=>{
 8       if(err) reject(err)
 9       resolve(data)
10     })
11   })
12 }
13 
14 function readM2() {
15   return new Promise((resolve,reject)=>{
16     fs.readFile('./resource/2.md', (err,data)=>{
17       if(err) reject(err)
18       resolve(data)
19     })
20   })
21 }
22 
23 function readM3() {
24   return new Promise((resolve,reject)=>{
25     fs.readFile('./resource/3.md', (err,data)=>{
26       if(err) reject(err)
27       resolve(data)
28     })
29   })
30 }
31 
32 async function main() {
33   // 因为前面的函数返回的是promise对象,这里就可以使用await,且promise的成功值就是我们要读取的文件数据
34   let m1 = await readM1()
35   let m2 = await readM2()
36   let m3 = await readM3()
37   console.log(m1)
38   console.log(m2)
39   console.log(m3)
40 }

 

posted @ 2021-12-22 17:19  凉之光ca  阅读(106)  评论(0)    收藏  举报