Nodejs在Async上创建简单队列

时间:2016-08-11 18:28:49

标签: javascript node.js

在下面的示例代码中我可以同时运行多功能

Promise.all([sendMoneyToRequestedUser(_data), saveTransferMoneyTransaction(_data)])
    .then(function (results) {
        log.info("OOOOOOOOOOOOOo");
    }).catch(function (error) {
    log.info(error)
});

但是我想为它们创建简单的队列,例如,我可以用Promise用这个解决方案实现吗?我有3个函数checksendpost,我想要连续运行并将每个步骤的结果传递给另一个。

第1步check()函数,第2步send()函数,然后在完成它们后执行函数,例如post()

对于这个实现我需要获得每个步骤的结果,例如从第1步得到结果,如果它返回true然后在第2步我需要使用结果第1步

是这个实现的async.parallel解决方案吗?或Promise可以这样做

3 个答案:

答案 0 :(得分:2)

更新:问题并不是很明确,所提供的内容以及所需的内容。从评论中,我得到以下内容:

提供了FROM wordpress:fpm ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update &&\ apt-get install -y unzip &&\ rm -rf /var/cache/apt/* ENV PLUGIN_URL https://downloads.wordpress.org/plugin ENV PIWIK_PLUGIN_VERSION 1.0.9 RUN curl -o /tmp/wp-piwik.${PIWIK_PLUGIN_VERSION}.zip ${PLUGIN_URL}/wp-piwik.${PIWIK_PLUGIN_VERSION}.zip &&\ unzip /tmp/wp-piwik.${PIWIK_PLUGIN_VERSION}.zip -d /tmp &&\ chown www-data:www-data /tmp/wp-piwik &&\ mv /tmp/wp-piwik /usr/src/wordpress/wp-content/plugins/&&\ find /usr/src/wordpress/wp-content/plugins/wp-piwik -type d -exec chmod 755 {} + &&\ find /usr/src/wordpress/wp-content/plugins/wp-piwik -type d -exec chmod 633 {} + &&\ ls -l /usr/src/wordpress/wp-content/plugins/ checksend的三个函数,希望它们能够串行运行。

假设提到的postchecksend都返回Promise,例如:

post

然后您可以按如下方式构建队列:

function check() {
  return new Promise(function (resolve, reject) {
    // Do some stuff and save them in a var 'results'
    var results = ...;
    resolve(results);
  });
}

在每个级别调用该函数,并从上一级别解析该值。

答案 1 :(得分:1)

我认为您正在寻找的是async.series。以顺序顺序依次运行一系列函数,并将结果数组传递给前一函数的回调。

示例

var async = require('async');

async.series([
    function(callback) {
        //Do a bunch of relevant stuff
        callback(null, 'First function');
    },
    function(callback) {
        //Do some more relevant stuff
        callback(null, 'Second function');
    }
],
function(err, results) {
    console.log(results); //Logs ['First function', 'Second function']
});

答案 2 :(得分:1)

在尝试使用各种模块时遇到了问题,最后我写了我可以想到的最简单的实现。

看看我写的这个简单的类(普通JS):

class Queue {
    constructor(maxSimultaneously = 1) {
        this.maxSimultaneously = maxSimultaneously;
        this.__active = 0;
        this.__queue = [];
    }

    /** @param { () => Promise<T> } func 
     * @template T
     * @returns {Promise<T>}
    */
    async enqueue(func) {
        if(++this.__active > this.maxSimultaneously) {
            await new Promise(resolve => this.__queue.push(resolve));
        }

        try {
            return await func();
        } catch(err) {
            throw err;
        } finally {
            this.__active--;
            if(this.__queue.length) {
                this.__queue.shift()();
            }
        }
    }
}

像这样使用它:

让我们说你有这个异步功能:

const printNumber = async (n) => {
    await new Promise(res => setTimeout(res, 2000)); // wait 2 sec
    console.log(n);
}

所以,而不是:

await printNumber(1);
await printNumber(2);
await printNumber(3);
await printNumber(4);

使用:

const q = new Queue();

q.enqueue(() => printNumber(1));
q.enqueue(() => printNumber(2));
q.enqueue(() => printNumber(3));
q.enqueue(() => printNumber(4));

每个功能都将在其他功能完成后执行。

输出:

1 // after 2 sec
2 // after 4 sec
3 // after 6 sec
4 // after 8 sec

或者您可以限制队列同时运行最多一些功能:

const q = new Queue(3);

q.enqueue(() => printNumber(1));
q.enqueue(() => printNumber(2));
q.enqueue(() => printNumber(3));
q.enqueue(() => printNumber(4));

输出:

1 // after 2 sec
2 // after 2 sec
3 // after 2 sec
4 // after 4 sec

,enqueue方法将从您的诺言中返回/抛出原始数据!

让我们假设您编写了一个用于上传文件的API,并且您希望同时限制最多上传5次。您希望一切保持不变,而不改变流程。这是您可以执行的操作:

async function upload(data) {
    // upload...
    if(something) {
        return 200;
    } else {
        throw 400;
    }
}

所以,不要这样做:

async function work(data) { 
    // do something...
    return await upload(data);
}

执行此操作:

const q = new Queue(5); // up to 5 at the same time
async function work(data) { 
    // do something...
    return await q.enqueue(() => upload(data));
}

class Queue {
    constructor(maxSimultaneously = 1) {
        this.maxSimultaneously = maxSimultaneously;
        this.__active = 0;
        this.__queue = [];
    }

    /** @param { () => Promise<T> } func 
     * @template T
     * @returns {Promise<T>}
    */
    async enqueue(func) {
        if(++this.__active > this.maxSimultaneously) {
            await new Promise(resolve => this.__queue.push(resolve));
        }

        try {
            return await func();
        } catch(err) {
            throw err;
        } finally {
            this.__active--;
            if(this.__queue.length) {
                this.__queue.shift()();
            }
        }
    }
}

const printNumber = async (n) => {
    await new Promise(res => setTimeout(res, 2000)); // wait 2 sec
    console.log(n);
}

async function start() {
    console.log('starting...');
    const q = new Queue();
    
    q.enqueue(() => printNumber(1));
    q.enqueue(() => printNumber(2));
    q.enqueue(() => printNumber(3));
    q.enqueue(() => printNumber(4));
}
Click this to run 1 log per 2 sec: <button onclick="start();">Start</button>

class Queue {
    constructor(maxSimultaneously = 1) {
        this.maxSimultaneously = maxSimultaneously;
        this.__active = 0;
        this.__queue = [];
    }

    /** @param { () => Promise<T> } func 
     * @template T
     * @returns {Promise<T>}
    */
    async enqueue(func) {
        if(++this.__active > this.maxSimultaneously) {
            await new Promise(resolve => this.__queue.push(resolve));
        }

        try {
            return await func();
        } catch(err) {
            throw err;
        } finally {
            this.__active--;
            if(this.__queue.length) {
                this.__queue.shift()();
            }
        }
    }
}

const printNumber = async (n) => {
    await new Promise(res => setTimeout(res, 2000)); // wait 2 sec
    console.log(n);
}

async function start() {
    console.log('starting...');
    const q = new Queue(3);
    
    q.enqueue(() => printNumber(1));
    q.enqueue(() => printNumber(2));
    q.enqueue(() => printNumber(3));
    q.enqueue(() => printNumber(4));
}
Click this to run up to 3 logs every 2 sec: <button onclick="start();">Start</button>