欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js异步操作大集合

程序员文章站 2024-03-16 14:04:28
...

1、为什么会有异步呢?

在javascript里,同步操作遇到加载量大时就会阻塞,这时候的用户体验并不好,如果采用异步操作,就不会阻塞。而且有的时候,我们想要某一个进程在几秒后再执行,而JavaScript的工作机制是同步的,这个时候就需要用到异步操作。一般来说,加载需要等待时间的就需要用到异步操作。

2、处理异步操作的几种方法

  • 回调(回调地狱)
  • 自定义事件
  • Promise
  • async以及await
    以上几种方法中,虽然promise和async以及await比较常用到,但是上面两种还是需要做一下笔记,我认为这些都是有借鉴意义的,所以我们一个一个来看吧。
    示例实现如下效果:一个红色方块先运动要left = 300px的地方 =>当运动到left = 300px时,转方向运动到top = 300px的地方 => 当运动到top = 300px时,转方向 运动到left = 0的地方 => 当运动到left = 0时,转方向运动到 top = 0的地方 js异步操作大集合

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就是简单大方美观!

相关标签: 前端 javascript