详解vue中async-await的使用误区

2020-06-14 06:12:49易采站长站整理

},
// step 2
mounted() {
let endTime;
const startTime = Date.now();
console.log(`start mounted: ${startTime}ms`);
console.log(this.list.rows);
endTime = Date.now();
console.log(`end mounted: ${endTime}ms, cost: ${endTime - startTime}ms`);
}

// step 1 => step 1.1 => step 1.2 => step 2

期望的打印结果是:


// step 1(created)
start created
// this.list
{__ob__: Observer}
end created
created cost: 3171.545166015625ms

// step 2(mounted)
start mounted
// this.list.rows
[{…}, __ob__: Observer]end mounted
mounted cost: 2.88623046875ms

对比实际的打印和期望的打印,就知道问题出在created钩子内使用了await的异步代码,并没有达到我们期望的那种的“异步代码同步执行”的效果,仅仅是一定程度上达到了这个效果。

下面来分析一下为什么会出现这个非预期的结果!

在分析前,让我们来回顾一下一些javascript的基础知识!看看下面这段代码:


(function __main() {
console.log('start');
setTimeout(() => {
console.log('console in setTimeout');
}, 0);
console.log('end');
})()

// output
start
end
console in setTimeout

这个打印顺序有没有让你想到什么?!

任务队列!

我们都知道JavaScript的代码可以分成两类:

同步代码 和 异步代码

同步代码会在主线程按照编写顺序执行;

异步代码的触发过程(注意是触发,比如异步请求的发起,就是在主线程同步触发的)是同步的,但是异步代码的实际处理逻辑(回调函数)则会在异步代码有响应时将处理逻辑代码推入任务队列(也叫事件队列),浏览器会在主线程(指当前执行环境的同步代码)代码执行完毕后以一定的周期检测任务队列,若有需要处理的任务,就会让队头的任务出队,推入主线程执行。

比如现在我们发起一个异步请求:


// exp-02
console.log('start');
axios.get('http://xxx.com/getList')
.then((resp) => {
console.log('handle response');
})
.catch((error) => {
console.error(error);
});
console.log('end');

在主线程中,大概首先会发生如下过程:


// exp-03
// step 1
console.log('start');

// step 2
axios.get('http://xxx.com/getList'); // 此时回调函数(即then内部的逻辑)还没有被调用

// step 3
console.log('end');

在看看浏览器此时在干什么!

此时事件轮询(Event Loop)登场,其实并非此时才登场,而是一直都在!