js异步操作大集合
程序员文章站
2024-03-16 14:04:28
...
JS的异步操作
1、为什么会有异步呢?
在javascript里,同步操作遇到加载量大时就会阻塞,这时候的用户体验并不好,如果采用异步操作,就不会阻塞。而且有的时候,我们想要某一个进程在几秒后再执行,而JavaScript的工作机制是同步的,这个时候就需要用到异步操作。一般来说,加载需要等待时间的就需要用到异步操作。
2、处理异步操作的几种方法
- 回调(回调地狱)
- 自定义事件
- Promise
-
async以及await
以上几种方法中,虽然promise和async以及await比较常用到,但是上面两种还是需要做一下笔记,我认为这些都是有借鉴意义的,所以我们一个一个来看吧。
示例实现如下效果:一个红色方块先运动要left = 300px的地方 =>当运动到left = 300px时,转方向运动到top = 300px的地方 => 当运动到top = 300px时,转方向 运动到left = 0的地方 => 当运动到left = 0时,转方向运动到 top = 0的地方
2.1.回调函数
css
*{
margin: 0;
padding: 0;
}
.box{
position: absolute;
width: 100px;
height: 100px;
background-color: red;
}
这里需要对box的position做absolute处理,才能设置left 和 top属性
html
<div class='box'></div>
js
let box = document.querySelector('.box')
function move(ele, end, dir, cb){
start = parseInt(window.getComputedStyle(ele, null)[dir])
let speed = end - start > 0 ? 1 : -1
setTimeout(() => {
start += speed
if(start === end){
// cb指回调函数,如果函数存在,就执行函数,为了容错,使程序不会崩溃
cb & cb()
}else{
ele.style[dir] = start + 'px'
// 这里用到递归
move(ele, end, dir, cb)
}
},10)
}
// 回调地狱,函数层层嵌套就是回调地狱
move(box, 300, 'left', function (){
move(box, 300, 'top', function (){
move(box, 0, 'left', function (){
move(box, 0, 'top', function (){
console.log('done')
})
})
})
})
层层嵌套的函数,让代码看上去并不雅观
2.2自定义监听函数
css和html部分同上
js
let box = document.querySelector('.box')
// 自定义事件需要使用到EventTarget里面的方法,比如addEventListener 或者 dispatchEvent,所以这里需要new EventTarget()
let customObj = new EventTarget()
let num = 1
function move(ele, end, dir){
start = parseInt(window.getComputedStyle(ele, null)[dir])
let speed = end - start > 0 ? 1 : -1
setTimeout(() => {
start += speed
if(start === end){
// 调用实例化的自定义事件,事件名称为myEvent1, myEvent2, myEvent3, myEvent3
customObj.dispatchEvent(new CustomEvent('myEvent' + num))
num ++
}else{
ele.style[dir] = start + 'px'
move(ele, end, dir)
}
},10)
}
move(box, 300, 'left')
customObj.addEventListener('myEvent1',() => {
move(box, 300, 'top')
})
customObj.addEventListener('myEvent2',() => {
move(box, 0, 'left')
})
customObj.addEventListener('myEvent3',() => {
move(box, 0, 'top')
// 同步执行,所以不会在move到top = 0 的时候再打印,没有阻塞情况
//console.log('none')
})
// 当start === end的时候,说明运动完毕,调用自定义监听函数。
customObj.addEventListener('myEvent4',() => {
console.log('done')
})
以上方法的逻辑:当方块运动到left = 300时,执行myEvent1,及执行move(box,300,‘top’),当top = 300时,执行myEvent2,执行move(box, 0, ‘left’),当left = 0时,执行myEvent3, 执行move(box, 0, ‘top’),当top = 0时,执行myEvent4,打印done。
2.3Promise
2.3.1Promise有三种状态
- pendding(等待)
let p = new Promise((res, rej) => {
console.log(111)
})
//返回promise对象,没有res和rej,状态pedding, promiseResult: undefined
console.log(p)
- fulfilled(成功)
let p = new Promise((res, rej) => {
res('ok')
})
//返回promise对象,状态fulfilled, result: ok
console.log(p)
- rejected(失败)
let p = new Promise((res, rej) => {
rej('error')
})
//返回promise对象,状态rejected, result: error
console.log(p)
2.3.2Promise对象的then方法
then有2个参数,onResolved, onRejected
let num = 1
let p = new Promise((res, rej) => {
num ? res('ok') : rej('err')
})
p.then((res) => {
// 这里是onResolved部分
console.log('成功', res)
},(rej) => {
// 这里是onRejected部分
console.log('失败', rej)
})
用catch也可以捕捉参数
let num = undefined
let p = new Promise((res, rej) => {
num ? res('ok') : rej('err')
})
p.then((res) => {
console.log('成功', res)
}).catch(err => {
console.log('失败', err)
})
2.3.3 then里的三种返还值
先执行同步操作,再执行异步操作
- 没有返还值,promiseResult为undefiend
let p = new Promise((res, rej) => {
res(1)
})
let p1 = p.then(res => {
console.log(res)
})
// Promise, fulfilled, result: undefined
// 1
console.log(p1)
- 返回普通值,promiseResult存储返回的普通值
let p = new Promise((res, rej) => {
res(1)
})
let p1 = p.then(res => {
console.log(res)
return 222
})
// Promise fulfilled result: 222
// 1
console.log(p1)
- 返还promise对象,可支持链式操作
let p = new Promise((res, rej) => {
res(1)
})
let p1 = p.then(() => {
return new Promise(res => {
res(222)
}).then(() => {
return new Promise(res => {
res(111)
})
})
})
// Promise fulfilled result: 111
console.log(p1)
2.3.4 Promise里的静态方法
let p1 = Promise.resolve('ok')
let p2 = Promise.reject('err')
// Promise fulfilled result: ok
console.log(p1)
// Promise rejected result: err
console.log(p2)
2.3.5 finally
不管成功与否,都要执行finally里面的语句
let p1 = new Promise((res, rej) => {
setTimeout(() => {
//res('ok1')
rej('err')
},2000)
})
p1.finally(() => {
console.log('done')
})
// done
2.3.6 Promise.all
如果所有的Promise都成功,就一次性打印他们的promiseResult
如果其中一个失败,就一个都不打印
let p1 = new Promise((res, rej) => {
setTimeout(() => {
res('ok1')
},2000)
})
let p2 = new Promise((res, rej) => {
setTimeout(() => {
res('ok2')
},1000)
})
Promise.all([p1, p2]).then((res) => {
console.log(res)
})
// ok1 ok2
2.3.7 Promise.race
哪个加载快,就打印哪一个,不管是不是成功
p1,p2代码同上
Promise.race([p1, p2]).then((res) => {
console.log(res)
})
// ok2
2.3.8 Promise.allSettled
不管成功与否,都打印
p1,p2代码同上
Promise.allSettled([p1, p2]).then(res => {
console.log(res)
})
// err ok2
2.4 async await
小demo
let fn1 = function (){
return new Promise((res, rej) => {
setTimeout(() => {
res(11)
}, 1000)
})
}
let fn2= function (){
return new Promise((res, rej) => {
setTimeout(() => {
res(22)
}, 2000)
})
}
let fn3 = function (){
return new Promise((res, rej) => {
setTimeout(() => {
res(33)
}, 3000)
})
}
// return 函数执行,才是一个Promise对象,如果return 一个函数,函数没有then方法,不能进行链式操作
// Promise对象就可以进行.then操作
// fn1().then(res => {
// console.log(res)
// return fn2()
// }).then(res => {
// console.log(res)
// return fn3()
// }).then(res => {
// console.log(res)
// })
async function asyncFn(){
try{
// res值从await返回值里接收
let res1 = await fn1()
console.log(res1)
let res2 = await fn2()
console.log(res2)
let res3 = await fn3()
console.log(res3)
}catch(e){
console.log(e)
}
}
asyncFn()
实现方块运动
js
let box = document.querySelector('.box')
let start
function move(ele, end, dir){
return new Promise(res => {
function fn(){
start = parseInt(window.getComputedStyle(ele, null)[dir])
let speed = end - start > 0 ? 1 : -1
setTimeout(() => {
start += speed
if(start === end){
res()
}else{
ele.style[dir] = start + 'px'
fn()
}
},10)
}
fn()
})
}
async function asyncFn(){
try{
await move(box, 300, 'left')
await move(box, 300, 'top')
await move(box, 0, 'left')
await move(box, 0, 'top')
console.log('所有运动完成')
}catch(e){
console.log(e)
}
}
asyncFn()
Endding:哇,async await就是简单大方美观!
下一篇: 如何实现自动化前端开发?