function __async(v) {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('CB:', v);
resolve(v);
}, 500);
});
}
/*
bad
nested .then()
puzzled
*/
__async(1).then(v => {
console.log(v);
__async(2)
.then(vv => {
console.log(vv);
__async(3).then(vvv => {
console.log(vvv);
})
})
});
/*
good
chain code
readable
*/
__async(1).then(v => {
console.log(v);
return __async(2);
}).then(v => {
console.log(v);
return __async(3);
}).then(v => {
console.log(v);
});
function queueOp() {
let qLocks = {};
function scheduleNextOp(qId) {
let opLock = qLocks[qId];
if (!opLock) {
return;
}
if (opLock.next.length === 0) {
delete qLocks[qId];
return;
}
let n = opLock.next.shift();
n.resolve(null);
}
/*
@param {String} qId, unique
@param {Function} op, function which returns a Promise
*/
return function(qId, op) {
return new Promise((resolve, reject) => {
let opLock = qLocks[qId];
if (!opLock) {
qLocks[qId] = opLock = {
next: []
}
resolve();
} else {
opLock.next.push({resolve, reject});
}
}).then(() => {
return op();
}).then((v) => {
scheduleNextOp(qId);
return v;
}).catch(e => {
scheduleNextOp(qId);
throw e;
});
}
}
test:
function __async(v, t) {
return new Promise((resolve, reject) => {
console.log(Date.now(), 'Start', v);
setTimeout(() => {
console.log(Date.now(), 'End', v);
resolve(v);
}, t);
});
}
try {
let myQueueOp = queueOp();
myQueueOp('test', () => {
return __async(1111, 1000);
});
myQueueOp('test', () => {
return __async(2222, 2000);
});
myQueueOp('test', () => {
return __async(3333, 1000);
});
} catch (e) {
console.error(e);
}
output:
1480915146233 'Start' 1111
1480915147239 'End' 1111
1480915147242 'Start' 2222
1480915149245 'End' 2222
1480915149246 'Start' 3333
1480915150247 'End' 3333
/*
@param {Number} step
@param {Array} ps, Array of function which returns a Promise
*/
function batchAsync(step, ps) {
let result = [];
return function batch(ps) {
if (ps.length > step) {
return Promise.all(ps.slice(0, step).map((f)=>f())).then(vs => {
console.log('Done:', vs);
result = result.concat(vs);
return batch(ps.slice(step, ps.length));
});
} else {
return Promise.all(ps.map((f)=>f())).then(vs => {
result = result.concat(vs);
console.log('Done:', vs);
return Promise.resolve(result);
});
}
}
}
test:
function __batch(v) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('CB:', v)
resolve(v);
}, 500)
});
}
let myBatch = batchAsync(5);
let ps = [];
for (let i = 0; i < 21; i++) {
ps.push(function() {
return __batch(i);
});
}
myBatch(ps).then(v => {
console.log('ALL DONE:', v);
}).catch(e => {
console.error('Batch error:', e)
});
output:
CB: 0
CB: 1
CB: 2
CB: 3
CB: 4
Done: [ 0, 1, 2, 3, 4 ]
CB: 5
CB: 6
CB: 7
CB: 8
CB: 9
Done: [ 5, 6, 7, 8, 9 ]
CB: 10
CB: 11
CB: 12
CB: 13
CB: 14
Done: [ 10, 11, 12, 13, 14 ]
CB: 15
CB: 16
CB: 17
CB: 18
CB: 19
Done: [ 15, 16, 17, 18, 19 ]
CB: 20
Done: [ 20 ]
ALL DONE: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]