ES6高级1:异步promise/async/await
程序员文章站
2023-12-26 21:02:21
...
什么是同步与异步
同步和异步是一种消息通知机制
- 同步阻塞
- 异步非阻塞
回调地域
ES5的回调就是在一个事件结束之后调用另一个事件
举例:小球四个方向的运动
如果一层嵌套一层一个个回调的话,回调数量一朵,就会非常难看,难以维护
move(ele, "left", 400, function () {
console.log("向右运动完成");
move(ele, "top", 400, function () {
console.log("向下运动完成!")
move(ele, "left", 0, function () {
console.log("向左运动完成");
move(ele, "top", 0, function () {
alert("运动完成");
})
})
});
});
所以es6就新增了promise方法实现
promise
- ES6的Promise对象是一个构造函数,用来生成Promise实例。
- 所谓Promise对象,就是代表了未来某个将要发生的事件(通常是一个异步操作)。
- 它的好处在于,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
两个参数、三种状态
- pending 等待中
- fulfilled / resolve 已成功
- reject 已失败:会抛出promise里面的错误
then 的两个参数
- resolve
- reject
对应promise里的两个参数
let p1 = new Promise((resolve, reject) => {
resolve("已完成")
// reject("抛出错误")
})
p1.then(res => {
console.log(res)
}, err => {
console.log(err)
})
then 的三种返回值
1 没有返回值
会拿到和之前状态一样的promise对象
let p1 = new Promise((resolve, reject) => {
resolve("已完成")
// reject("抛出错误")
})
let result = p1.then(res => {
console.log(res)
})
console.log(result)
2 有返回值
返回的就是promise对象
let result = p1.then(res => {
console.log(res)
return "values"
})
console.log(result)
3 直接返回 new promise对象
let result = p1.then(res => {
console.log(res)
return new Promise((resolve, reject) => {
resolve("已完成2");
})
})
链式操作
p1.then(res => {
console.log(res)
return new Promise((res => {
res("已完成2")
}))
}).then(res => {
console.log(res)
return new Promise((res, reject) => {
reject("抛出错误")
})
}).catch(err => {
console.log(err)
})
Promise的静态方法
let p1 = new Promise((res,reject)=>{
setTimeout(()=>{
res(1);
},2000)
})
let p2 = new Promise((res, reject) => {
setTimeout(()=> {
res(2)
}, 1000)
})
let p3 = new Promise((res, reject) => {
setTimeout(()=> {
res(3)
}, 3000)
})
1 Promise.all 等待所有结果
Promise.all([p1, p2, p3]).then(res => {
console.log(res);
})
2 .race 只拿到执行最快的结果
Promise.race([p1, p2, p3]).then(res => {
console.log(res);
})
3 直接执行结果或者异常
let p4 = Promise.resolve("完成");
let p5 = Promise.reject("抛出异常")
console.log(p4, p5)
async await
其实promise并不是最好的解决回调地域的方法
因为promise仍有很多缺点
- 无法取消Promise,一旦新建它就会立即执行
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
- 当处于pending状态时,无法得知目前进展到哪一个阶段
于是es7又有一个新的特性:async与await,与promise配合使用,将Promise变为同步的写法
用法
用async声明一个函数,在这个函数里面使用await 跟一个Promise对象
这样会使Promise对象从上往下按顺序同步执行
async function asyncFn() {
let res = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(111);
resolve("value1");
}, 2000)
})
console.log(res);
let res2 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(222);
resolve("value2");
}, 1000)
})
console.log(res2);
}
asyncFn();
捕获异常
想从外部捕获Promise内的异常需要try{}catch{}
捕获到错误之后就会终止函数
async function asyncFn() {
try {
let res3 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(333);
reject("错误");
}, 1000)
})
console.log(res3);
let res5 = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(444);
resolve("完成")
}, 500)
})
console.log(res5);
} catch (e) {
console.log("error: ", e)
}
}
asyncFn();
使用Promise实现小球运动
function move(ele, direction, target, cb) {
return new Promise((resolve, reject) => {
let start = parseInt(window.getComputedStyle(ele, null)[direction]);
let speed = (target - start) / Math.abs(target - start) * 5;
console.log(speed)
function fn() {
// 向右 加 向左 减
start += speed;
ele.style[direction] = start + "px";
if (start === target) {
resolve("运动完成");
} else {
window.requestAnimationFrame(fn)
}
}
fn();
})
}
let ele = document.querySelector(".box");
move(ele, "left", 400).then(res => {
return move(ele, "top", 400);
}).then(res => {
return move(ele, "left", 0);
}).then(res => {
return move(ele, "top", 0);
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
使用async await改写小球运动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0px;
top: 0px;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
function move(ele, direction, target, cb) {
return new Promise((resolve, reject) => {
let start = parseInt(window.getComputedStyle(ele, null)[direction]);
let speed = (target - start) / Math.abs(target - start) * 5;
console.log(speed)
function fn() {
// 向右 加 向左 减
start += speed;
ele.style[direction] = start + "px";
if (start === target) {
resolve("运动完成");
} else {
window.requestAnimationFrame(fn)
}
}
fn();
})
}
let ele = document.querySelector(".box");
async function asyFunc() {
try {
let m1 = await move(ele, "left", 400)
console.log("向右", m1)
let m2 = await move(ele, "top", 400);
console.log("向下", m1)
let m3 = await move(ele, "left", 0);
console.log("向左", m1)
let m4 = await move(ele, "top", 0);
console.log("向上", m1)
} catch (e) {
console.log(e)
}
}
asyFunc();
</script>
</html>
推荐阅读
-
ES6高级1:异步promise/async/await
-
js异步回调Async/Await与Promise的区别,Async/Await替代Promise的6个理由
-
同步和异步(promise,async,await)
-
vue中使用async、await和promise实现异步API的同步调用
-
es6 异步 之async await 学习总结
-
Promise(es6)和await,async(es7)
-
JS基于ES6新特性async await进行异步处理操作示例
-
async/await与promise(nodejs中的异步操作问题)
-
JS基于ES6新特性async await进行异步处理操作示例
-
详解koa2学习中使用 async 、await、promise解决异步的问题