前端开发-关于异步编程
异步编程
本篇主要介绍关于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 }

浙公网安备 33010602011771号