一文带你简单封装JS下的异步任务对象

 更新时间:2022年11月17日 10:43:47   作者:头疼脑胀的代码搬运工  
我们在烧水的过程中去干了别的事情,就属于异步模式,异步模式中不会等待异步任务的结束才开始执行下一个同步的任务,都是开启过后就立即执行下一个任务,下面这篇文章主要给大家介绍了如何通过一文带你简单封装JS下的异步任务对象的相关资料,需要的朋友可以参考下

废话开篇:

js有微任务跟宏任务,但是不管是哪种任务并不代表着会开辟新的线程,可以理解为将上述两种任务放到“主任务”之后执行,有点像iOS下的在主线程调用异步函数一样,其实也只是将异步任务降低了优先级,等主线程不忙的时候再处理该任务,比如:UI任务优先级较高,所以,任何的主线程下的异步任务都要排到UI任务结束之后进行。

一、利用 Promise 实现异步任务

利用 Promise 实现异步任务,如果不加任何限制,微任务的执行便会按添加的先后顺序进行执行。这里简单封装一下,实现微任务下的执行依赖。可能有人会问,await 不就行了吗?是的,声明异步方法就能满足,顺序执行。但是还是要整理一个过程来增加对代码的理解。

二、实现效果

这里简单的逻辑是:异步3任务 -> 异步2任务 -> 异步1任务

三、代码实现

下面是调度代码逻辑

function dispath(){
    console.log('异步3完成,异步2才能开始,异步2完成,异步1才能开始')
    //创建任务一
    let blockOperationOne = new BlockOperation((b)=>{
        console.log('异步1任务');
        //单一任务完成事件通知
        b.finished();
    });

    //添加新任务
    blockOperationOne.addExecutionBlock((b)=>{
        console.log('异步1新增任务');
        b.finished();
    });

    //创建任务二
    let blockOperationTwo = new BlockOperation((b)=>{
        console.log('异步2任务');
        b.finished();
    });

    blockOperationTwo.addExecutionBlock((b)=>{
        console.log('异步2新增任务2');
        b.finished();
    });

    blockOperationTwo.addExecutionBlock((b)=>{
        console.log('异步2新增任务需要等待4秒');
        setTimeout(() => {
            console.log('异步2新增任务3');
            b.finished();
        }, 4000);
    });

    //创建任务三
    let blockOperationThree = new BlockOperation((b)=>{
        console.log('异步3需要等待1秒');
        setTimeout(() => {
            console.log('异步3任务');
            b.finished();
        }, 1000);
    });

    //添加依赖
    blockOperationOne.addDependency(blockOperationTwo);
    blockOperationTwo.addDependency(blockOperationThree);

    //开始执行
    blockOperationOne.start();
    blockOperationTwo.start();
    blockOperationThree.start();

    console.log('我是宏任务');
};

下面是封装的 BlockOperation 对象

//任务通知对象
class Block{
    //完成回调
    doneCallBack = null
    constructor(doneCallBack){
        this.doneCallBack = doneCallBack
    }

    //单任务完成
    finished(){
        this.doneCallBack();
    }
}

//任务对象
class BlockOperation {
    //任务集合
    blocks = []
    //是否已开始
    isBeginStart = false
    //依赖任务对象
    dependencyOperation = null
    //被依赖影响的对象
    impactOperation = null
    //全部完成的事件判定
    allOperationIsDone = false
    //全部完成的事件回调
    allOperationDoneBlock = ()=>{
        //将依赖任务完成进行自身任务
        if(this.impactOperation){
            this.impactOperation.start()
        }
    };

    //代理
    proxy = null;
    //代理set方法
    handler = {
        set(target,property,value){
            target[property] = value
            if(property == 'allOperationIsDone' && value){
                //执行闭包回调
                target.allOperationDoneBlock();
            }
            return true
         },
        get(target,property){
            return target[property]
        }
    }

    //初始化
    constructor(cb){
        this.blocks.push(cb)
        this.addObserver()
    }

    //添加观察者
    addObserver(){
        this.proxy = new Proxy(this, this.handler)
    }

    //添加新任务
    addExecutionBlock(cb){
        this.blocks.push(cb)
    }
    
    //添加依赖
    addDependency(blockOperation){
        this.dependencyOperation = blockOperation
        blockOperation.impactOperation = this
    }

    //开始异步任务
    start(){
        const self = this
        self.isBeginStart = true
        //先判断是否有依赖
        if(this.dependencyOperation && this.dependencyOperation.allOperationIsDone == false){
            //这里加一个定时器(目的是添加一个相对靠后的宏任务来检查所有的任务是否都执行了开启,不是很严谨)
            setTimeout(()=>{
                if(self.dependencyOperation.isBeginStart == false){
                    throw Error('请检查是否有依赖任务未开启')
                }
            },0)
            //等待依赖的执行完
            return
        }
        self.blocks.forEach((operationBlock) => {
            Promise.resolve(operationBlock).then((res)=>{
                if(res){
                    res(new Block(()=>{
                        //删除任务
                        delete self.blocks[self.blocks.indexOf(res)]
                        //过滤null(防止delete执行后数组中有null占位)
                        self.blocks = self.blocks.filter((item) => {
                            return item
                        })
                        //判断是否全部完成
                        self.proxy.allOperationIsDone = (self.blocks.length == 0)
                    }))
                };
            })
        });
    }
}

四、总结与思考

其实 async / await 的使用是可以避免回调的,但是,这里并不是去用它的特性来优化代码,而是用 Promisethen 函数是微任务来处理异步,目的就是将一些不太重要的逻辑放到主任务之后,这里也是参考了 iOS 下的 NSBlockOperation 的一些 api 命名,语言间实现代码虽然不同,但却存在着互通的设计思路吧。

到此这篇关于封装JS下异步任务对象的文章就介绍到这了,更多相关JS异步任务对象封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IE6-IE9中tbody的innerHTML不能赋值的解决方法

    IE6-IE9中tbody的innerHTML不能赋值的解决方法

    这篇文章主要介绍了IE6-IE9中tbody的innerHTML不能赋值的解决方法,需要的朋友可以参考下
    2014-06-06
  • 微信小程序实现验证码获取倒计时效果

    微信小程序实现验证码获取倒计时效果

    这篇文章主要为大家详细介绍了微信小程序实现验证码获取倒计时效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 浅谈javascript语法和定时函数

    浅谈javascript语法和定时函数

    初学者可能对Javascript的定时器有误解,认为它们是线程,其实Javascript是运行于单线程中的,而定时器仅仅是计划在未来的某个时间执行,而具体的执行时间是不能保证的,因为在页面的生命周期中,不同的时间可能有其它代码在控制Javascript的里进程。
    2015-05-05
  • JavaScript中统计Textarea字数并提示还能输入的字符

    JavaScript中统计Textarea字数并提示还能输入的字符

    是在文本框中输入文字的时候,会自动统计输入的字符,并显示用户还能输入的字符,其实js也可以实现,下面就以示例的方式为大家讲解下
    2014-06-06
  • Electron实现应用打包、自动升级过程解析

    Electron实现应用打包、自动升级过程解析

    这篇文章主要介绍了Electron实现应用打包、自动升级过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • js实现简单贪吃蛇游戏

    js实现简单贪吃蛇游戏

    这篇文章主要为大家详细介绍了js实现简单贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • 利用iscroll4实现轮播图效果实例代码

    利用iscroll4实现轮播图效果实例代码

    iScroll 4 这个版本完全重写了iScroll这个框架的原始代码。这个项目的产生完全是因为移动版webkit浏览器(诸如iPhone,iPad,Android 这些系统上广泛使用)。下面这篇文章主要介绍了利用iscroll4实现轮播图效果的方法教程,需要的朋友可以参考下。
    2017-01-01
  • JavaScript实现鼠标移动事件画笔

    JavaScript实现鼠标移动事件画笔

    这篇文章主要为大家详细介绍了JavaScript实现鼠标移动事件画笔,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • javascript实现智能手环时间显示

    javascript实现智能手环时间显示

    这篇文章主要为大家详细介绍了javascript实现智能手环时间显示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • Js中将Long转换成日期格式的实现方法

    Js中将Long转换成日期格式的实现方法

    这篇文章主要介绍了Js中将Long转换成日期格式的实现方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06

最新评论