🔥🔥🔥“异步”是好还是坏?怎么灵活使用?看这边!🔥🔥🔥
前言
今天我们来聊一聊JS中的代码“异步”问题。先让我们简单看一看下面的代码:
function a() {
setTimeout(() => {
console.log('写文章');
}, 1000)
}
function b() {
setTimeout(() => {
console.log('发布');
}, 0)
}
a()
b()
我们分别设置了a
、b
两个函数;再分别设置一个计时器,a
函数设定为1秒,b
函数设定为0秒;最后分别调用a
、b
两函数。我们都知道JavaScript是从上往下单线程执行的,很明显此处我们想要的效果肯定是先“写文章
”,1秒后再“发布
”,让我们看看效果:
很可惜事与愿违,我们连“写文章
”都还没写呢就已经“发布
”了。
那么为什么会这样呢?当代码读取到调用a
函数时,确实是是先执行了a
函数,但同时浏览器引擎也不会傻傻等待a
函数执行完再进行下一步,它会同时也执行b
函数。而根据我们的设定,b
函数的计算器设定为0秒并不需要等待,所以我们先得到的就是“发布
”,而不是预期的“写文章
”。这就是“异步”。
正文
异步问题
在JavaScript
中,异步编程是一种处理非阻塞操作的方式,使得代码可以在等待某些操作完成的同时继续执行其他任务。JavaScript是从上往下单线程执行的,但通过异步编程,可以实现在等待一些I/O操作、网络请求或定时器等时不阻塞整个程序的执行。同一时间干多步事情,让JS执行效率更高——这就是异步的优点。但异步有好处
也有坏处
,举个“栗子”:当b
需要拿到a
给出的结果才能执行的时候,异步会让还未拿到a
结果的b
也执行,这就会出问题,也就叫异步问题。就像我们前言
中展示的那样,那碰到这种问题该怎么解决呢?
回调(Callback)
有一种老的解决办法就是回调:把b的执行扔进a,等a执行完自然就轮到了b。让我们简单试一试:
function a() {
setTimeout(() => {
console.log('写文章');
b()
}, 1000)
}
function b() {
setTimeout(() => {
console.log('发布');
}, 0)
}
a()
再看看执行结果:
我们在等待了一秒之后完成了“写文章
”随后立即“发布
”了。这样确实看起来解决了异步问题,但这也同时会带来新的问题。在回调中我们有一种情况叫做“回调地狱”:当回调的数量多起来的时候,执行的链就会非常长,类似于物理中的串联,有一个元件出了问题,整段代码就会崩掉,并且代码维护起来也会非常麻烦,得从头到尾查找问题。以下是一个简单的“回调地狱”例子,使用了多个嵌套的回调函数,模拟了异步操作的情况:
// 模拟异步操作1
function asyncOperation1(callback) {
setTimeout(function() {
console.log("Async Operation 1 completed");
callback();
}, 1000);
}
// 模拟异步操作2
function asyncOperation2(callback) {
setTimeout(function() {
console.log("Async Operation 2 completed");
callback();
}, 1000);
}
// 模拟异步操作3
function asyncOperation3(callback) {
setTimeout(function() {
console.log("Async Operation 3 completed");
callback();
}, 1000);
}
// 嵌套回调地狱
asyncOperation1(function() {
asyncOperation2(function() {
asyncOperation3(function() {
console.log("All async operations completed");
});
});
});
在上述例子中,asyncOperation1
、asyncOperation2
和 asyncOperation3
分别代表三个异步操作。它们的回调函数嵌套在彼此之内,形成了回调地狱。当异步操作数量增加时,这种嵌套结构会变得难以理解和维护。因此,使用Promise
或更先进的异步处理方式通常更为推荐。这有助于避免回调地狱,提高代码的可读性和可维护性。
Promise
在JavaScript
中,Promise
是一种用于处理异步操作的对象,它提供了更优雅的方式来组织和处理异步代码。Promise
可以通过.then()
链式调用,使得多个异步操作可以依次执行,而不是嵌套在回调中,使得异步代码更易于理解
和维护
,避免了回调地狱(Callback Hell)。还可以通过.then()
方法处理Promise
成功状态,通过.catch()
方法处理Promise
失败状态。这种分离成功和失败的处理方式更加清晰。
下面是一个简单的Promise
示例:
// 创建一个Promise对象
let myPromise = new Promise(function(resolve, reject) {
// 异步操作
setTimeout(function() {
let success = true;
if (success) {
resolve("Promise resolved!");
} else {
reject("Promise rejected!");
}
}, 1000);
});
// 处理Promise成功状态
myPromise.then(function(result) {
console.log(result);
})
// 处理Promise失败状态
.catch(function(error) {
console.error(error);
});
在这个例子中,myPromise
表示一个异步操作,通过resolve
和reject
函数表示成功和失败。.then()
方法用于处理成功状态,.catch()
方法用于处理失败状态。Promise
的引入使得异步代码更为结构化,便于阅读
和维护
。
结语
这次文章我们简单介绍了JavaScript
中的“异步”、“回调”以及“Promise对象”。当然Promise
身为一个对象肯定远不止这么几个方法!JavaScript
的世界是那么的广阔,如果关于JS的内容对你有帮助的话,希望能给博主一个免费的小心心♡呀~
来源:juejin.cn/post/7301914624140034083