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

目录
  • 废话开篇:
  • 一、利用 Promise 实现异步任务
  • 二、实现效果
  • 三、代码实现
  • 四、总结与思考

废话开篇:

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异步任务对象封装内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Nest.js参数校验和自定义返回数据格式详解

    0x0 参数校验 参数校验大部分业务是使用 Nest.js 中的管道 方法实现,具体可以查阅文档 .不过编写过程中遇到一些问题,虽然文档讲得比较晦涩. 在做个查询接口,里面包含一些参数,做成 dto 结构数据: import { ApiProperty } from '@nestjs/swagger' export class QueryUserDto { @ApiProperty({ required: false, description: '页码' }) readonly currentP

  • json数据格式常见操作示例

    本文实例讲述了json数据格式常见操作.分享给大家供大家参考,具体如下: json数据格式 第一种,对象形式 <script> //var json3={name:"longzhoufeng",age:123}//第一种方式 var json3={"name":"longzhoufeng","age":123}//推荐这种方式,加引号,安全性高一点,转换格式好一些 for( var attr in json3){

  • nestjs返回给前端数据格式的封装实现

    一般开发过程中不不会根据httpcode来判断接口请求成功与失败的,而是会根据请求返回的数据,里面加上code字段 一.返回的数据格式对比 1.直接返回的数据格式 { "id": 1, "uuid": "cbbe7abc-b95e-48a0-8d24-b1ac93c45328", "name": "哈士奇1", "age": 12, "color": null, &q

  • JS封装转换前后端接口数据格式工具函数下划线<=>大写

    目录 一.前言 二.思路 三.代码 四.效果 结语 一.前言 这段时间接近年底,公司的业务也不是很繁忙,有些闲暇的时间,就模仿ruoyi写一个后台系统,技术栈前端是react18,后端为koa2: 在一个接口返回数据的过程中,遇到一个问题,就是后端数据保存到数据库中的命名标准是下划线,而前端的这边的命名标准是驼峰命名,所以如果直接将从数据库的数据返回给前端,便非常不优雅,网上想直接找工具包,也没找到合适的,故而自己手写了一个,如果有同样需求的小伙伴们,可以直接拿去用. 二.思路 一般后端返回给前

  • JS中Promise的使用及封装方式

    目录 Promise 是什么 Promise 的特点 Promise 的缺点 Promise 的原理 Promise 的方法 1. Promise.prototype.then() 2. Promise.prototype.catch() 3. Promise.prototype.finally() 4. Promise.all() 5. Promise.race() 5. Promise.allSettled() Promise 的简单封装 总结 Promise 是什么 Promise 是异步

  • 使用纯JavaScript封装一个消息提示条功能示例详解

    目录 介绍 思路&布局 操作逻辑 完整代码 介绍 一个类似Element UI.Ant-Design UI等 UI 框架的消息提示功能,方便在任何网页环境中直接调用函数使用:区别在不依赖 js 及 css 引用,而是使用纯 js 进行封装实现,代码更精简,同时保持和 UI 框架一样的视觉效果(可自行修改成自己喜欢的样式) 代码仓库 在线预览效果(点击[登录].[点击复制]按钮时触发提示效果) 思路&布局 先来写单个提示条,并实现想要的过渡效果,最后再用逻辑操作输出节点即可:这里不需要父节点

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

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

  • 一文带你搞懂JS中六种For循环的使用

    目录 一.各个 for 介绍 1.for 2.for ... in 3.for ... of 4.for await...of 5.forEach 6.map 二.多个 for 之间区别 1.使用场景差异 2.功能差异 3.性能差异 三.for 的使用 for 循环在平时开发中使用频率最高的,前后端数据交互时,常见的数据类型就是数组和对象,处理对象和数组时经常使用到 for 遍历,因此下班前花费几分钟彻底搞懂这 5 种 for 循环.它们分别为: for for ... in for ... o

  • 简单封装js的dom查询实例代码

    最近一直在啃犀牛书,有感,于是写了个简单的js的dom查询 $ = function (val) { switch(val.charAt(0)) { case '#' : return document.getElementById(val.substring(1)); break; case '.' : val = val.replace('.',''); if(document.getElementsByClassName) return document.getElementsByClas

  • 自定义的一个简单时尚js下拉选择框

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

  • 浅谈关于JS下大批量异步任务按顺序执行解决方案一点思考

    前言 最近需要做一个浏览器的, 支持大体积文件上传且要支持断点续传的上传组件, 本来以为很容易的事情, 结果碰到了一个有意思的问题: 循环执行连续的异步任务, 且后一个任务需要等待前一个任务的执行状态 这么说可能有点空泛, 以我做的组件举例: 这个组件本意是为了上传大体积视频, 和支持断点续传, 因为动辄几个G的视频不可能直接把文件读进内存, 只能分片发送(考虑到实际网络状态, 每次发送大小定在了4MB), 而且这么做也符合断点续传的思路. 组件工作流程如下: 选定上传文件后, 从H5原生upl

  • 用原生JS对AJAX做简单封装的实例代码

    首先,我们需要xhr对象.这对我们来说不难,封装成一个函数. var createAjax = function() { var xhr = null; try { //IE系列浏览器 xhr = new ActiveXObject("microsoft.xmlhttp"); } catch (e1) { try { //非IE浏览器 xhr = new XMLHttpRequest(); } catch (e2) { window.alert("您的浏览器不支持ajax,请

  • iOS下拉选择菜单简单封装

    本文实例为大家分享了简单封装的iOS下拉选择菜单代码,供大家参考,具体内容如下 // // OrderListDownMenu.h #import <UIKit/UIKit.h> @protocol OrderListDownMenuDelegate <NSObject> - (void)OrderListDownMenu:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; @end

  • JS简单封装的图片无缝滚动效果示例【测试可用】

    本文实例讲述了JS简单封装的图片无缝滚动效果.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="

  • js+csss实现的一个带复选框的下拉框

    效果图: css: <style type="text/css"> /* 带复选框的下拉框 */ ul li{ list-style: none; padding:0px; margin: 0px; } .select_checkBox{ border:0px solid red; position: relative; display:inline-block; } .chartQuota{ height:23px; float:left; display:inline-

  • JS+CSS实现简单的二级下拉导航菜单效果

    本文实例讲述了JS+CSS实现简单的二级下拉导航菜单效果.分享给大家供大家参考.具体如下: 这是一款CSS配合JavaScript实现二级下拉导航菜单,好像CSS要配合JS才能写出好效果来,本款菜单同样用到了JS,菜单目前支持两级,下拉导航是我们经常用的一种菜单形式,把这个修改一下你就能用了,结构挺简单,相信你会做好的. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-css-simple-2l-fade-down-menu-codes/

随机推荐