注册
web

Js中异步代码挂起怎么解决?

从下面代码引入问题


function a() {
console.log('aa');
}

function b() {
setTimeout(() => { //异步代码
console.log('bb');
}, 1000)
}

function c() {
console.log('cc');
}

a()
b()
c()

上述代码的执行结果为先打印'aa',再打印'cc',等一秒后再打印'bb'。哎?我们是不是就有疑问了,我们明显是先调用的函数a,再调用的函数b,最后调用的函数c,为什么函数b的打印结果最后才出来呢?这里我们要清楚的是函数b中定义了一个计时器,执行此代码是需要时间的,属于异步代码,当浏览器执行到此代码时,会先将此程序挂起,继续往下执行,最后才会执行异步代码。那要怎么解决此类问题呢?一个方法是将其他函数体内也定义一个计时器,这样也就会按顺序调用了,但是这样太不优雅了;还一个方法是函数c作为参数传入函数b,在函数b中执行掉,这样也不优雅。es6出来后就可以使用promise来解决此问题了。


js是一种单线程语言


什么是单线程?


我们可以理解为一次只能完成一个任务,如果有其他任务进来,那就需要排队了,一个任务完成了接着下一个任务。



因为js是一种单线程语言,任务是按顺序执行的,但是有时我们有多个任务同时执行的需求,这就需要异步编程的思想。



什么是异步?


当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情。


什么是异步模式调用? 


前一个任务执行完,调用回调函数而不是进行后一个任务。后一个任务不等前一个任务结束就执行,任务排列顺序与执行顺序无关。


什么是回调函数?


把函数当作参数传入另一个函数中,不会立即执行,当需要用这个函数时,再回调运行()这个函数。



以前是通过回调函数实现异步的,但是回调用多了会出现回调地狱,导致爆栈。



举个用回调函数来解决异步代码挂起问题


<body>
<div class="box">
<audio src="" id="audio" controls></audio> </audio>
</div>
<script>
//ajax
let url = ''
function getSong(cb) {
$.ajax({
url: ' 数据地址',
dataType: 'json',
success(res) {
console.log(res);
url = res[0].url
cb()
}
})
}
getSong(playSong)

function playSong() {
let audio = document.getElementById('audio')
window.addEventListener('click', () => {
audio.src = url
window.onclick = function () {
audio.play()
}
})
}

</script>
</body>

代码中用ajax向后端获取数据,这是需要时间的,属于异步代码,当我们分开调用这两个函数,函数getSong中的异步代码会出现挂起状态,导致函数playSong中的url获取不到值,会出现报错的情况,运用回调函数可以很好地解决这个问题。


Promise的使用


先执行一段代码


function xq() {

setTimeout(() => {
console.log('老王');
}, 2000)

}


function marry() {
setTimeout(() => {
console.log('老王结婚了');
}, 1000)
}


function baby() {
setTimeout(() => {
console.log('小王出生了');
}, 500)
}
xq()
marry()
baby()

结果为


1.png


???这是不是有点违背了道德,只能说老王是个渣男。这时候我们就需要使用promise对象来调整一下顺序了。


function xq() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('老王去相亲');
resolve('ok')
}, 2000)
})
}


function marry() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('老王结婚了');
resolve('ok')
}, 1000)
})
}


function baby() {
setTimeout(() => {
console.log('小王出生了');
}, 500)
}


// xq().then(() => {
// marry().then(() => {
// baby()
// })
// })
xq()
.then(marry)
.then(baby)
// xq().then(marry)
// baby()

在这里我们可以理解为老王相亲的时候疯狂对相亲对象promise,才有了后面的步入婚姻的殿堂,结婚后想生个娃也要对妻子疯狂的promise,才有了后面的小王出生了。


老王长叹了一口气,终于通过promise挽回了形象。


小结


Js异步编程方法不只这两种,还有比如事件监听,发布/订阅,生成器函数 Generator/yield等。需要我们一起去探索研究,毕竟‘学无止境’。


作者:一拾九
来源:juejin.cn/post/7225257817345884221

0 个评论

要回复文章请先登录注册