js中有四种可以实现异步处理的方法;依次是以下四项:
-
回调(会造成回调地狱)
-
自定义事件
-
Promise
-
async及await
下面结合一个应用实例依次用四种方法实现进行学习;要求div从左端向右移动200px,接着向下移动200px,再向左移动200px,再向上移动200px,回到最初始的位置;
1、回调函数
通过调用move方法依次实现向右、向下、向左、向上移动; 其中一个移动完成之后进行下一个移动;
function move(ele, target, dir, cb) {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
let speed = target - startLeft > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
cb && cb();
} else {
ele.style[dir] = startLeft + "px";
move(ele, target, dir, cb);
}
}, 10)
}
let ele = document.querySelector(".box");
move(ele, 300, "left", function () {
console.log("向右运动完成");
move(ele, 300, "top", function () {
console.log("向下运动完成");
move(ele, 0, "left", function () {
console.log("向左运动完成");
move(ele, 0, "top", function () {
console.log("向上运动完成");
});
});
});
});
2、自定义事件
通过EventTarget对象的dispatchEvent和addEventListener方法在完成一个移动之后进行下一次移动;move方法中不再需要回调函数cb(),而是需要派发对应的自定义事件;
let eventObj = new EventTarget();
let num = 1;
function move(ele, target, dir) {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
let speed = target - startLeft > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
eventObj.dispatchEvent(new CustomEvent("myEvent"+num));
num++;
} else {
ele.style[dir] = startLeft + "px";
move(ele, target, dir);
}
}, 10)
}
let ele = document.querySelector(".box");
move(ele, 300, "left");
eventObj.addEventListener("myEvent1", function() {
console.log("向右运动完成,触发向下运动事件");
move(ele, 300, "top");
})
eventObj.addEventListener("myEvent2", function() {
move(ele, 0, "left");
console.log("向下运动完成,触发向左运动事件");
})
eventObj.addEventListener("myEvent3", function() {
console.log("向左运动完成,触发向上运动事件");
move(ele, 0, "top");
})
eventObj.addEventListener("myEvent4", function() {
console.log("向上运动完成,运动结束");
})
3、Promise方法
move方法中返回一个Promise对象,调用move方法时使用then方法来接收Promise对象中的完成情况,然后进行下一次调用move方法,调用move方法的同时,将这个move方法返回,也就是返回这个promise对象,这样可以再次使用then方法接收promise的返回值,这样依次使用,即可实现效果;
function move(ele, target, dir) {
return new Promise(resolve => {
function fn() {
let startLeft = parseInt(getComputedStyle(ele, null)[dir]);
let speed = target - startLeft > 0 ? 1 : -1;
setTimeout(() => {
startLeft += speed;
if (startLeft === target) {
resolve("运动完成")
} else {
// .dir报错 下边两行的顺序
ele.style[dir] = startLeft + "px";
// move(ele, target, dir);
fn();
}
}, 10)
}
fn();
})
}
let ele = document.querySelector(".box");
move(ele, 300, "left").then(res => {
console.log(res, "向右");
return move(ele, 300, "top")
}) .then(res => {
console.log(res, "向下");
return move(ele, 0, "left")
}).then(res => {
console.log(res, "向左");
return move(ele, 0, "top")
}).then(res => {
console.log(res, "向上");
})
4、async await方法*
move方法和promise方法一样 调用时使用async await方法
let ele = document.querySelector(".box");
async function asyncFn() {
try {
let res1 = await move(ele, 300, "left");
console.log("向右", res1);
let res2 = await move(ele, 300, "top");
console.log("向下", res2);
let res3 = await move(ele, 0, "left");
console.log("向左", res3);
let res4 = await move(ele, 0, "top");
console.log("向上", res4);
} catch (err) {
console.log(err);
}
}
asyncFn();