注册
web

🔥🔥🔥“异步”是好还是坏?怎么灵活使用?看这边!🔥🔥🔥

前言


    今天我们来聊一聊JS中的代码“异步”问题。先让我们简单看一看下面的代码:


function a() {
setTimeout(() => {
console.log('写文章');
}, 1000)
}

function b() {
setTimeout(() => {
console.log('发布');
}, 0)
}

a()
b()

    我们分别设置了ab两个函数;再分别设置一个计时器a函数设定为1秒,b函数设定为0秒;最后分别调用ab两函数。我们都知道JavaScript是从上往下单线程执行的,很明显此处我们想要的效果肯定是先“写文章”,1秒后再“发布”,让我们看看效果:


image.png


    很可惜事与愿违,我们连“写文章”都还没写呢就已经“发布”了。


    那么为什么会这样呢?当代码读取到调用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()

再看看执行结果:


image.png


    我们在等待了一秒之后完成了“写文章”随后立即“发布”了。这样确实看起来解决了异步问题,但这也同时会带来新的问题。在回调中我们有一种情况叫做“回调地狱”:当回调的数量多起来的时候,执行的链就会非常长,类似于物理中的串联,有一个元件出了问题,整段代码就会崩掉,并且代码维护起来也会非常麻烦,得从头到尾查找问题。以下是一个简单的“回调地狱”例子,使用了多个嵌套的回调函数,模拟了异步操作的情况:


// 模拟异步操作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");
});
});
});

    在上述例子中,asyncOperation1asyncOperation2asyncOperation3 分别代表三个异步操作。它们的回调函数嵌套在彼此之内,形成了回调地狱。当异步操作数量增加时,这种嵌套结构会变得难以理解和维护。因此,使用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表示一个异步操作,通过resolvereject函数表示成功和失败。.then()方法用于处理成功状态,.catch()方法用于处理失败状态。Promise的引入使得异步代码更为结构化,便于阅读维护


结语


    这次文章我们简单介绍了JavaScript中的“异步”、“回调”以及“Promise对象”。当然Promise身为一个对象肯定远不止这么几个方法!JavaScript的世界是那么的广阔,如果关于JS的内容对你有帮助的话,希望能给博主一个免费的小心心♡呀~


作者:Mio_02
来源:juejin.cn/post/7301914624140034083

0 个评论

要回复文章请先登录注册