概述
有时候下面的代码有参数需要从上面执行的异步函数中获取,但是当异步函数没有执行完时,下面的代码就执行完了(此时参数为空),从而出错
由于JavaScript是单线程的,所以代码的执行是同步的,代码从上至下执行,这里贴一下JavaScript代码的执行顺序:(原因可以查看下面的JavaScript运行机制)
- 同步代码,包括promise的构造函数
- promise.then()中的代码
- setTimeout函数,关于该函数的等待时间:最小值不得小于4毫秒,如果低于这个值,则默认是4毫秒
JavaScript运行机制
同步代码(包括promise的构造函数)在执行栈中执行,同时异步任务按顺序进入异步任务队列(队列是先进先出
的),然后将异步任务分配到微任务队列(nextTick,Promise.then())和任务队列(DOM,AJAX,setTimeout,setImmediate)
同步代码执行完毕后,微任务队列中的异步任务依次进入执行栈并执行,每次进入一个,执行完毕后再进入下一个,这就是Event Loop(事件循环),最后执行任务队列的异步任务
解决办法
我们可以使用Promise保证程序的执行顺序,此时虽然问题解决了,但是Promise使用起来会有点繁琐,我们可以使用async
和await
关键词简化操作
代码实现
初始代码
f1
和f3
都执行完毕后,f2
内的代码才会执行,原因查看上面的JavaScript运行机制
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 33 34 35
| const flag = ref();
const f1 = () => { console.log('f1'); }
const f2 = () => { setTimeout(() => { console.log('f2'); flag.value = true; }, 3000); }
const f3 = (flag) => { console.log('f3'); if (flag) { console.log('函数f2将flag的值设置成了true'); } else { console.log('函数f2没有及时将flag的值设置成true'); } }
const init = () => { f1(); f2(); f3(flag.value); }
init();
|
控制台输入如下图所示,结果会输出函数f2没有及时将flag的值设置成true
,且f2
排在最后
上面的结果并不符合我们的预期(上面的代码执行完后才执行下面的),我们的预期是输出函数f2将flag的值设置成了true
,且f2
排在f1
和f3
之间,如下图所示
使用Promise
f2
这个函数的结果是返回一个Promise对象,在.then()
中执行f3
可以保证:f2
执行完了之后才开始执行f3
,此时已经把问题解决了
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 33 34 35 36 37 38 39 40 41 42 43 44
| const flag = ref();
const f1 = () => { console.log('f1'); }
const f2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('f2'); flag.value = true; }, 3000); }); }
const f3 = (flag) => { console.log('f3'); if (flag) { console.log('函数f2将flag的值设置成了true'); } else { console.log('函数f2没有及时将flag的值设置成true'); } }
const init = () => { f1();
f2().then(res => { console.log(res); f3(flag.value); }); }
init();
|
使用async和await简化
使用async
和await
关键词不但可以简化代码以提高代码的可读性,还可以避免回调地狱
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 33 34 35 36 37 38
| const flag = ref();
const f1 = () => { console.log('f1'); }
const f2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('f2'); flag.value = true; }, 3000); }); }
const f3 = (flag) => { console.log('f3'); if (flag) { console.log('函数f2将flag的值设置成了true'); } else { console.log('函数f2没有及时将flag的值设置成true'); } }
const init = async () => { f1(); const res = await f2(); console.log(res); f3(flag.value); }
init();
|
PS.
Promise中文文档:Promise - JavaScript | MDN (mozilla.org)