js中异步处理的四种实现方式

594 阅读2分钟

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();