Skip to content

Instantly share code, notes, and snippets.

@odesskij
Created September 14, 2017 10:14
Show Gist options
  • Save odesskij/56ca17de17db31315e4c413f317b787e to your computer and use it in GitHub Desktop.
Save odesskij/56ca17de17db31315e4c413f317b787e to your computer and use it in GitHub Desktop.
function manager(tasks, worker, concurrency) {
const res = [];
function assign(w) {
return new Promise((resolve) => {
const t = tasks.shift();
if (t === undefined) {
return resolve();
}
console.log('assign %s', t);
return w(t).then((r) => res.push(r))
.then(() => assign(w))
.then(resolve);
});
}
return Promise.all(Array.from(new Array(concurrency)).map(() => assign(worker)))
.then(() => res)
}
function worker(t) {
return new Promise((r) => setTimeout(r, Math.random() * 1000))
.then(() => `r_${t}`)
}
// Test
manager(
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
worker,
3
).then((r) => console.log(r));
@tomfun
Copy link

tomfun commented Sep 14, 2017

Refactored

/**
 * Analog of Bluebird.map, it does {concurrency} tasks at the time.
 * Main differences with Bluebird.map:
 * * it do tasks in the same order
 * * it doesn't retain order of results (result array is in another order than input)
 * @param {Array<*>} arrayOfArguments array of any objects, mutated
 * @param {Function} callback callback function that will accept one element of arrayOfArguments
 * @param {Number} concurrency number of parallel doing callbacks
 * @mutateProp arrayOfArguments
 * @return {Promise<Array<*>>} array of results of callback
 */
function manager(arrayOfArguments, callback, concurrency) {
    const res = [];

    function assign(w) {
        if (!arrayOfArguments.length) {
            return;
        }
        const t = arrayOfArguments.shift();
        console.log('assign %s', t);
        return w(t)
            .then((r) => res.push([t, r]))
            .then(() => assign(w))
    }

    return Promise.all(new Array(concurrency).fill(0).map(() => assign(callback)))
        .then(() => res)
}

Usage

function worker(t) {
    const time = Math.random() * 1000 + 200;
    return new Promise((r) => setTimeout(r, time))
    //.then(() => console.log('done %s', t))
        .then(() => `${t} - ${time}`)
}

manager([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], worker, 3).then((r) => console.log(r))

Output

assign 0
assign 1
assign 2
assign 3
assign 4
assign 5
assign 6
assign 7
assign 8
assign 9
assign 10
[ [ 0, '0 - 513.0302493939919' ],
  [ 2, '2 - 877.2288212758475' ],
  [ 1, '1 - 1103.057211444951' ],
  [ 3, '3 - 1108.9664378402958' ],
  [ 4, '4 - 776.9573875839455' ],
  [ 5, '5 - 1158.510915029161' ],
  [ 6, '6 - 646.6538371628075' ],
  [ 7, '7 - 749.4339405561612' ],
  [ 8, '8 - 721.4084924717506' ],
  [ 10, '10 - 928.9708082480082' ],
  [ 9, '9 - 1087.1047580706036' ] ]

@tomfun
Copy link

tomfun commented Sep 14, 2017

My code is the same, but keep order of results, so it more close with bluebird.map

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment