async/await使用
async/await是ES8引入的新语法,用来简化Promise异步操作。在此之前,我们只能用链式.then( )的方式处理Promise异步操作
async/await的基本使用
- 如果某个方法的返回值是Promise实例对象,使用await修饰后就是一个真正的值(promise的结果值)
- 如果一个方法内部用到了await,则这个方法必须使用async来修饰(这两个关键字是成对出现的)
import thenFs from 'then-fs' // 按照顺序读取文件1,2,3的内容 async function getAllFile(){ const r1 = await thenFs.readFile('./files/1.txt','utf8') console.log(r1) const r2 = await thenFs.readFile('./files/2.txt','utf8') console.log(r2) const r3 = await thenFs.readFile('./files/3.txt','utf8') console.log(r3) } getAllFile()
- async函数是一个特殊的函数,其返回结果是一个promise对象,这个对象的状态由它修饰的函数内部return语句决定
网络异常,图片无法展示
|
- 如果await修饰的promise对象是失败的状态,则需要用try{ }catch(e){ }来捕获错误
网络异常,图片无法展示
|
注意事项
在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行 (异步任务会等同步任务执行完后才执行)
import thenFs from 'then-fs' console.log('A') async function getAllFile(){ console.log('B') const r1 = await thenFs.readFile('./files/1.txt','uft8') const r2 = await thenFs.readFile('./files/2.txt','uft8') const r3 = await thenFs.readFile('./files/3.txt','uft8') console.log(r1, r2, r3) console.log('D') } getAllFile() console.log('C') // 最终的输出顺序 A B C 111 222 333 D // console.log('B')是同步执行的,console.log(r1, r2, r3)和console.log('D')是异步执行的 // 在打印完B后,js主线程就退出了后续代码的执行(异步任务等同步任务执行完之后再执行),接着就执行console.log('C') // 当异步的操作结束后就开始打印r1, r2, r3,最后打印D
EventLoop
javascript是一门单线程执行的编程语言。即同一时间只能做一件事
单线程执行任务队列问题:
如果前一个任务非常耗时,则后续的任务就不得不一直在等待,从而导致程序假死的问题
为了防止某个耗时任务导致程序假死的问题,JS把待执行的任务分为两类:
1. 同步任务(synchronous)
- 又称为非耗时任务,指在主线程上排队执行的任务
- 只有前一个任务执行完成,才会执行后一个任务
2. 异步任务(asynchronous)
- 又称为耗时任务,异步任务由JS委托给宿主环境进行执行(宿主环境就是JS的执行环境,比如是在浏览器运行JS的,那么浏览器就是JS的宿主环境;如果是在node.js中执行JS的,那么node就是宿主环境)
- 当异步任务执行完成后,会通知JS主线程执行异步任务的回调函数
网络异常,图片无法展示
|
JS主线程执行完同步任务后,会从"任务队列"中读取异步任务的回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以这种运行机制又被称为EventLoop(事件循环)
宏任务和微任务
JS把异步任务进行了划分
- 宏任务(macrotask)
异步Ajax请求、setTimeout( )和setInterval( ) 、文件操作、其他宏任务
- 微任务(microtask)
Promise.then( ), .catch( ), .finally( ) 、process.nextTick、其他微任务
宏任务与微任务的执行顺序
网络异常,图片无法展示
|
注意:每一个宏任务执行完后都会检查是否存在待执行的微任务
**在执行完同步任务后,会在异步任务队列中查找微任务,若存在微任务则会优先执行微任务。所有微任务执行完之后才执行下一个宏任务
// 分析下面代码的执行顺序 setTimeout(function(){ console.log(1) }) new Promise(function(resolve){ console.log(2) resolve() }).then(function(){ console.log(3) }) console.log(4) // 正确的输出顺序是2431 // setTimeout 是宏任务,会放到宏任务队列中等待执行 // new Promise 是同步任务。所以会先输出2。然后.then()是微任务,会放到微任务队列中等待执行 // 接着会输出4。此时执行完了同步任务,会读取任务队列中的任务,检查是否存在微任务,因此输出3 // 执行完所有微任务后,就执行下一个宏任务,即输出1