首页 > JS如何实现一个异步队列来按顺序执行函数?

JS如何实现一个异步队列来按顺序执行函数?

asyn([func1, func2, func3], function(){
    // func1,func2,func3全部按顺序执行完的回调
})

Promise 大法好!

var funcs = [func1, func2, func3];
var funcPromise = funcs.map(function(func, i) {
    return new Promise(function(resolve) {
        func();
        console.log('func'+(i+1)+' well done!');
        resolve();  //如果 func 是异步方法的话需要把 resolve 定义到方法的 callback 中
    });
});
Promise.all(funcPromise).then(function() {
    console.log('all well done');
});

更爽一点可以直接用 async/await


var funcs = [func1, func2, func3];
(async () => {
    for(let i=0;i<funcs.length;i++) {
        await funcs[i]();
        console.log('func'+(i+1)+' well done');
    }
    console.log('all well done');
})()

简单实现的顺序执行,和并行执行的工具类
使用方法

var ac = AsyncCaller();
ac.pushQueue(asyncFunc1,args);
ac.pushQueue(asyncFunc2,args);
ac.exec(function(){
    console.log('tasks finished');
});

function asyncFunc1(){
    ajax.get(url,function(){
        dealWithComponentConfig.resolve(ac);
    })
}
function asyncFunc2(){
    ajax.post(url,function(){
        dealWithComponentConfig.resolve(ac);
    })
}
function AsyncCaller(){
    var allTasksPool = [];
    var queueTasksPool = [];
    Function.prototype.resolve = function(ac){
        ac.aysncFunRunOver.call(ac, this);
    };
    this.pushAll = function(asyncFunc,arguArr){
        if(queueTasksPool.length === 0){
            var funcObj = {'func':asyncFunc,'argu':arguArr};
            allTasksPool.push(funcObj);
        }else {
            console.error(errorMsg);
        }
        return this;
    };
    this.pushQueue = function(asyncFunc,arguArr){
        if(allTasksPool.length === 0){
            var funcObj = {'func':asyncFunc,'argu':arguArr};
            queueTasksPool.push(funcObj);
        }else{
            console.error(errorMsg);
        }
        return this;
    };

    this.aysncFunRunOver = function(caller){
        if(execType === "queue"){
            if(queueTasksPool.length === 0){
                if(this.finalFunc){
                    //delete Function.prototype.resolve;
                    this.finalFunc();
                }
            }else{
                var funcObj = queueTasksPool[0];
                queueTasksPool.shift();
                funcObj.func.apply(this,funcObj.argu);

            }
        }else if(execType === "all"){
            for (var i = 0; i < allTasksPool.length; i++) {
                var task = allTasksPool[i];
                if(caller === task.func){
                    allTasksPool.splice(i,1);
                    break;
                }
            }
            if(allTasksPool.length === 0){
                if(this.finalFunc){
                    //delete Function.prototype.resolve;
                    this.finalFunc();
                }
            }
        }
    };
    var execType = "queue";
    this.exec = function(callback){
        this.finalFunc = callback;
        if(allTasksPool.length > 0){
            execType = "all";
            executeAll();
        }else if(queueTasksPool.length > 0){
            execType = "queue";
            executeQueue();
        }else{
            this.finalFunc.call();
        }

    };
    function executeQueue(){
        var funcObj = queueTasksPool[0];
        queueTasksPool.shift();
        funcObj.func.apply(null,funcObj.argu);

    }
    function executeAll(){
        for(var i=0;i<allTasksPool.length;i++){
            var funcObj = allTasksPool[i];
            funcObj.func.apply(null,funcObj.argu);
        }
    }
    var errorMsg = "Only one type of task can be executed at same time";
}

function asyn(funsArray,resultCallback){
    var funExecResult=[];
    var executor=(function(){
        var index=0;
        return {
            next:function(){
                if(index< funsArray.length){
                    return funsArray[index++];
                }else{
                    return null;
                }
            }
        }
    }());

    (function doNext(){
        var nextFun=executor.next();
        if(nextFun){
            funExecResult.push(nextFun.call(null));
            doNext();
        }else{
            resultCallback.apply(null, funExecResult);
        }
    }());
    
}

https://github.com/caolan/async#waterfall 比较符合

async.waterfall([
    function(callback) {
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback) {
      // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback) {
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
    // result now equals 'done'
});

我这里假设你的这几个func都是能够返回Promise的异步函数,然后我们来写一个asyn方法:

var asyn = function(arr, cb) {
    arr
        .reduce((p, func) => p.then(func), Promise.resolve())
        .then(cb);
};

现在来测试一下:

var func1 = function() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('func1');
            resolve();
        }, 500);
    });
};
var func2 = function() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('func2');
            resolve();
        }, 300);
    });
};
var func3 = function() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('func3');
            resolve();
        }, 100);
    });
};

asyn([func1, func2, func3], function() {
    console.log('all things gets done');
});
//func1
//func2
//func3
//all things gets done
【热门文章】
【热门文章】