开发过程你遇到过吗?
一、为什么会写这篇文章?
最近在维护公司项目的时候遇到了一个场景问题,大概代码我写成简略版如下:
let data = null //method2需要的数据
let data1 = null
function fn() {
method1();
method2(data);
console.log(data1);
}
fn();
function method1() {
// 模拟请求
setTimeout(() => {
data = "method1";
}, 100);
}
function method2(currentData) {
method3(currentData + '----' + 'method2')
}
function method3(currentData) {
// 模拟请求
setTimeout(() => {
data1 = currentData;
}, 500);
}
想必大家看到这个会觉得异常熟悉,没错就是事件循环(Event Loop)。
什么是事件循环?
由于JavaScript是单线程的,一次只能执行一个任务,可是那么多任务堆在一起时,该怎么去处理呢?
为了解决这个问题,JavaScript引擎创建了执行栈来管理任务,首先将所有的任务都放在执行栈中,通过同步方式执行栈中的任务,当遇到异步任务时,将异步任务挂起,当异步任务有了结果后,再将异步任务添加到执行栈中,等待执行。
具体细节请查看:JavaScript运行机制详解:再谈Event Loop
那么上面代码我想做到fn函数中的data1能够正常打印出method1----method2的结果,应该怎么进行修改呢?
于是就有了下面的改造方案:
let data = null //method2需要的数据
let data1 = null
async function fn() {
await method1();
await method2(data);
console.log(data1);
}
fn();
function method1() {
// 模拟请求
new Promise((resolve, reject) => {
setTimeout(() => {
data = "method1";
resolve();
}, 100);
});
}
function method2(currentData) {
new Promise((resolve, reject) => {
method3(currentData + '----' + 'method2').then(() => {
resolve();
});
});
}
function method3(currentData) {
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
data1 = currentData;
resolve();
}, 500);
});
}
神奇的事情发生了?
输出为:null
我不信邪在输出data1的时候给了个5s的定时器
async function fn() {
await method1();
await method2(data);
settimeout(() => {
console.log(data1);
}, 5000);
}
神奇的事情发生了?
输出为:null----method2
这时候我陷入了思考?
- 思考1:为什么未赋值成功,函数在遇到await的时候不是应该暂停等待执行完了,再往后执行吗?
- 思考2:同步走到method2的时候data在method1中未被赋值成功。
二、于是带着疑惑去仔细阅读了下async/await的相关资料
发现如下:
- 发现一:await等待一个异步执行的完成
什么意思呢?
简单来说,await后面如果是个异步函数,他会暂停后面的执行,直到异步函数执行完,并返回一个Promise.resolve()结果后,继续执行下面的代码。
肯定有人会问,Promise.reject()呢?
结果是:Promise.reject()会直接抛出错误,并终止后续的代码执行。
注意这段话:直到异步函数执行完,并返回一个Promise.resolve()结果后,继续执行下面的代码。
- 发现二:既然await等待异步函数的执行,那把函数编程异步不就行了?
三、带着上面的发现,来重新写下代码
let data = null //method2需要的数据
let data1 = null
async function fn() {
await method1();
await method2(data);
console.log(data1);
}
fn();
function method1() {
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
data = "method1";
resolve();
}, 100);
});
}
function method2(currentData) {
return new Promise((resolve, reject) => {
method3(currentData + '----' + 'method2').then(() => {
resolve();
});
});
}
function method3(currentData) {
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
data1 = currentData;
resolve();
}, 500);
});
}
咦???我们发现对了。
输出结果:method1----method2
带着上面代码,我们很容易发现,原来是自己没有return出Promise.resolve()的结果导致的
四、总结
- 在阅读别人文章时候,还是得仔细阅读,这就是平时没有仔细阅读外加没有多动手调试导致的。
- 基础还是要多补补。
- 仔细阅读下相关资料的源码这时候就非常有必要,比如:async/await
五、参考资料
六、今年暂定大目标
- 阅读完经典的javascript相关书籍
- 学习Vue3源码
- 深入学习TypeScript,并进行实战
- 深入学习Node.js
七、最后
第一次写文章总结,如有错误,请大佬们指出,望轻喷!!!!
你们还能有什么新的实现手段呢?可以评论区回复一起学习哦。