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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值