zoukankan      html  css  js  c++  java
  • js函数整合队列顺序执行插件

    前言

    在日常开发中,也许我们会遇到这样的一个问题。我们利用【发布订阅模式】(如果不了解的可以直接访问此链接www.cnblogs.com/xiaoxiaokun… )去执行【发布】事件时,遇到函数内部涉及到异步执行时,就比较难以处理。为了满足这种需求,我专门写了一个这样的插件用于函数整合队列并顺序执行。

    函数队列循环执行

    /**
    *1.0.0.1版本
    */
    var list=[];//存储函数
    list.push(function(){
        console.log(1);
    });
    list.push(function(){
        console.log(2);
    });
    list.push(function(){
        console.log(3);
    });
    for (var i=0;fn=list[i++];) {
        fn();//执行
    }

    结果:1,2,3
    这是最简单的方式,可以实现函数整合成一个队列,按照先进先出顺序执行。现在在仔细看发现,如果函数中有异步执行那函数执行就不能保证按照顺序执行,例如:

    var list=[];//存储函数
    list.push(function(){
        console.log(1);
    });
    list.push(function(){
        setTimeout(function() {
            console.log(2);
        }, 2000);
    });
    list.push(function(){
        console.log(3);
    });
    for (var i=0;fn=list[i++];) {
        fn();//执行
    }

    输出的结果肯定是 1,3,2

    /**
    *1.0.0.2版本
    */
    var list=[];
    list.push(function(){
        console.log(1);
    });
    list.push(function(){
        console.log(2);
    });
    list.push(function(){
        console.log(3);
    });
    
    function start(list){
        if(list.length){
            list.shift()();
            arguments.callee(list);
        }
    }
    start(list);

    这种方式可以等到执行完毕,清除list内部执行过后的函数。不影响下次push 执行。但是异步函数还是未解决。

    /**
    *1.0.0.3版本
    */
    var list=[];//存储数组的集合
    list.push(function(){
        console.log(1);
    });
    list.push(function(callback){
        //callback是代表这个函数是异步的函数
        setTimeout(function() {
            console.log(2);
            callback();//执行完异步函数执行回调函数
        }, 2000);
    });
    list.push(function(){
        console.log(3);
    });
    
    function start(){
        //判断数组的长度
        if(list.length){
            var fn=list.shift();//取出数组第一个函数
            //判断函数是否带有参数
            if(fn.length){
                fn(start);//执行该函数,并且把 start本身传递进去。
            }else{
                fn();
                start();
            }
        }
    }
    start();

    此版本可以解决带有异步执行的函数按照刚开始push进去的顺序依次执行。
    需要注意的是,如果函数是内部带有异步执行的函数,需要传递一个参数来告诉start。但是如果我们push进去的函数本身有好多个参数这需要怎么办呢!!接下来看另一版本。

    /**
    *1.0.0.4版本
    */
    var list=[];//存储数组的集合
    list.push(function(){
        console.log(1);
    });
    list.push(function(callback){
        setTimeout(function() {
            console.log(2);
            callback();
        }, 2000);
    });
    list.push(function(){
        console.log(3);
    });
    
    function start(){
        //判断数组的长度
        if(list.length){
            var fn=list.shift();//取出数组第一个函数
            //判断函数是否带有参数
            if(fn.length && getfunarg(fn)[0]=='callback'){
                fn(start);//执行该函数,并且把 start本身传递进去。
            }else{
                fn();
                start();
            }
        }
    }
    start();
    /**
     * 查找函数参数名
     * @fn {Function } 要查找的函数
     * @return []返回参数数组
     * */
    function getfunarg(fn) {
        var f = /^[s(]*function[^(]*(s*([^)]*?)s*)/.exec(fn.toString());
        return f && f[1] ? f[1].split(/,s*/) : [];
    }

    到现在为止,我们这几个函数基本已经满足我们的需求,但是push的时候,假设函数多个参数,我们还需进一步优化代码!为了把这个插件做的更好。我决定还是把callback放在最后,这样就能保证函数传递参数不受影响。

    最终版本

    /**
     * 作者:小小坤
     * 联系:java-script@qq.com
     * 日期:2017-11-11
     * 版本:1.0.0.4
     *     -----------使用说明----------
     * 1、把所有函数【包含异步执行的函数】按照顺序依次 使用lk.push存入
     * 2、带有参数的函数,一定要注意{最一个参数如果是callback}会被认为是 异步执行函数
     * 3、异步执行的函数,需要把最一个参数设置为callback。并在函数执行完毕执行callback();函数保证按照顺序执行
     * 
     * */
    ;! function() {
        var list = [], //存储函数的列表
            isFun = Object.prototype.toString; //用于验证是否是函数
        /**
         * 添加到列表中
         * @fn {Function} 函数体
         * */
        function push(fn) {
            isFun.call(fn) === "[object Function]" && list.push(fn);
        };
        /**
         * 开始执行列表中的所有函数,
         * 按照先进先出原则
         * 
         * */
        function star() {
            if(list.length) {
                var fn = list.shift(),//截取第一个函数
                arry=getfunarg(fn),//获取这个函数的参数列表
                _length=arry.length;//参数列表的长度
                if(_length && arry[_length-1] === 'callback') {
                    if(_length===1){
                        fn(star);
                    }else{
                        arry.pop();//删除最后一个参数
                        arry.push(star);//把回调函数存入数组
                        fn.apply(this,arry);
                    }
                } else {
                    fn.apply(this,arry);
                    star(); 
                }
            }
        }
        /**
         * 查找函数参数名
         * @fn {Function } 要查找的函数
         * @return []返回参数数组
         * */
        function getfunarg(fn) {
            var f = /^[s(]*function[^(]*(s*([^)]*?)s*)/.exec(fn.toString());
            return f && f[1] ? f[1].split(/,s*/) : [];
        }
        //挂在到Windows上。
        window.lk = {
            push: push,
            start: star
        }
    }();
    //使用测试
    /**--------一条华丽的分割线--------**/
    var a=100,
    b=200,
    d=300,
    f=400;
    
    //定义函数 a2  ,此函数带有一个参数,被认为是异步函数
    function a2(a,b,callback) {
        console.time('2');
        setTimeout(function() {
            console.timeEnd('2');
            callback();
            console.log(a,'a');
        }, 1000);
    }
    //把函数函数 a2 放入数组
    lk.push(a2);
    
    //定义函数 a3
    function a3(d, f) {
        console.log(f,'f');
        console.log(3);
    }
    //把函数函数 a3 放入数组
    lk.push(a3);
    
    //定义函数 a4 此函数带有一个参数,被认为是异步函数
    function a4(callback) {
        console.time('4');
        setTimeout(function() {
            console.timeEnd('4');
            callback();
        }, 2000);
    }
    //把函数函数 a4 放入数组
    lk.push(a4);
    
    //最后开始执行
    lk.start();

    最终此插件完成,需要压缩的同学可以自行压缩。代码比较简单,提供了两个方法。
    push存储函数列表
    start开始执行

    总结

    通过上边的代码编写我们学到了处理函数列表时候,需要考虑到异步函数。处理异步函数,需要回调函数参与。这样就能帮助代码按照顺序执行。

  • 相关阅读:
    ReactJs入门
    Studio-Class Diagram
    Visual Studio-Sequence Diagram
    架构、职责、数据一致性
    Microsoft Build 2015
    Net下无敌的ORM
    SpringMVC1
    插件式Web框架
    ASP.NET的CMS
    Android Drawable绘图学习笔记(转)
  • 原文地址:https://www.cnblogs.com/xiaoxiaokun/p/7838377.html
Copyright © 2011-2022 走看看