「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。
异步与同步
- 说起 js,大家都知道它是单线程执行的
- 如果它是多线程的,那么代表它在同一时刻就能执行多个任务
- 例如两个任务,一个任务修改 dom, 同时另一个任务删除此 dom,那么浏览器就不知道该怎么操作 dom 了
- 所以为了保证 web 应用的交互一致性,而被设计成单线程执行
- 如果程序中的任务都是普通的同步任务,那么按照单线程的执行逻辑,依次执行每个任务即可
- 但是往往我们的应用程序,不会只包含同步任务,往往也会涉及到异步的网络请求等任务,那 js 引擎该如何处理呢,答案就是使用 callback 回掉函数
- 将下一个任务作为回掉传给上一个任务执行,当上一个任务执行完后,立即执行回掉
用回掉函数解决异步问题
- 下面就是一个典型案例用回掉来解决 setTimeout 带来的异步问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
position: absolute;
width: 200px;
height: 200px;
background-color: teal;
/* left: 0; */
}
</style>
</head>
<body>
<div class="box"></div>
<script>
let move = (ele, direction, target, cb) => {
let start = parseInt(getComputedStyle(ele, null)[direction]);
let speed = ((target - start) / Math.abs(target - start)) * 2;
start += speed;
ele.style[direction] = `${start}px`;
setTimeout(() => {
if (Math.abs(target - start) <= 2) {
ele.style[direction] = `${target}px`;
cb & cb();
} else {
move(ele, direction, target, cb);
}
}, 10);
};
let ele = document.querySelector(".box");
move(ele, "left", 301, () => {
console.log("右移 ok");
move(ele, "top", 301, () => {
console.log("下移 ok");
move(ele, "left", 0, () => {
console.log("左移 ok");
move(ele, "top", 0, () => {
console.log("上移 ok");
});
});
});
});
</script>
</body>
</html>
- 上面的实现逻辑很简单,通过 setTimeout 每隔 10ms 去执行一次 move 函数,move 函数接收要移动的终点值,当移动到终点后,执行回掉函数,即传入的下个动画函数
- move 函数的实现也很简单
- 接收四个参数,依次是:需要操作的 dom 元素,dom 元素移动的方向,dom 元素移动的终点值,回掉函数
- 通过 getComputedStyle API 获取 dom 元素最新的样式
- 我们的 dom 元素初始状态的坐标是 (0,0), 那么当 dom 元素向右和向下移动时,speed 为正值,当 dom 元素向左和向上移动时,speed 为负值
- move 函数每次执行,都需要将关于移动的属性值更新一下
- 在 setTimeout 中,若 dom 元素已经到达终点,则调用下个移动的回掉函数,否则按照当前方向继续移动dom 元素
小结
- 尽管上面已经实现了,我们想要的元素移动的效果
- 但是实现的代码,未免太不优雅,形成了传说中的回掉地狱,极其不利于代码阅读与维护
- 为了解决这个问题,我的下篇文章将会介绍一种相对优雅的实现方式:基于自定义事件的异步操作
最后
- 今天的分享就到这里了,欢迎大家在评论区里面进行讨论 👏。
- 如果觉得文章写的不错的话,希望大家不要吝惜点赞,大家的鼓励是我分享的最大动力 🥰