I am listening to user events and some of these depend on the completion of others. Dealing with these events is an asynchronous task, so I use promises.
Let's say I've got this:
A
-> B
-> C
-> ...
-> D
-> E
-> ...
-> F
My initial approach was to save a promise for A
and attach the handling of B
using the then
method of A
's promise. The same for B
and C
... D
and D
and E
... F
.
But these events can happen almost in the same time, and B
can happen before A
. Since I cannot listen to a promise that not exists yet... How would you resolve this?
My idea is to define an object for each level (A, B, D), where I can attach a promise and the handling of future events. When attaching a promise, I would iterate the handling of future events and set them to the promise's then
. When attaching a future event, I would look if there is a promise, and attach that to it's then
or save that into an array or something.
Do you know an existing solution that already solves this issue or shall I follow with my idea?
Thank you.
Further clarification as requested:
I'm listening to multimedia events in the client side that are forwarded via websocket (using socket.io) to the server. The order of the events is indeed first A, then B, etc. But since some of them happen almost at the same time, they can be processed out of order.
Example code
let promiseForA, promiseForB;
socket.on('A', data => {
promiseForA = asynchronousTaskForA();
});
socket.on('B', data => {
// What if promiseForA has not yet been defined?
promiseForA.then(neededValue => {
asynchronousTaskForB(neededValue);
});
});
socket.on('C', data => {
// What if promiseForB has not yet been defined?
promiseForB.then(neededValue => {
asynchronousTaskForC(neededValue);
});
});
socket.on('D', data => {
// What if promiseForB has not yet been defined?
promiseForB.then(neededValue => {
asynchronousTaskForD(neededValue);
});
});
function asynchronousTaskForA() {
// something
resolve('something needed by B');
}
function asynchronousTaskForB(value) {
// something with value
resolve('something needed by C ... D');
}
function asynchronousTaskForC(value) {
// something with value
resolve();
}
function asynchronousTaskForD(value) {
// something with value
resolve('something needed by E ... F');
}
My idea
So... it works. It may be an anti-pattern, wrong or insane, but... I'd like to know of a better alternative.
let PromiseWaiter = function() {
let promise = null;
let thens = [];
let self = this;
this.setPromise = function (p) {
promise = p;
thens.forEach(t => {
p.then(t);
});
};
this.then = function(t) {
if (promise === null) {
thens.push(t);
} else {
promise.then(t);
}
return self;
};
this.reset = function() {
promise = null;
thens = [];
};
};
module.exports = PromiseWaiter;
Using it:
let waitForA = new PromiseWaiter();
let waitForB = new PromiseWaiter();
let waitForD = new PromiseWaiter();
socket.on('A', data => {
waitForA.setPromise(asynchronousTaskForA());
});
socket.on('B', data => {
waitForA.then(neededValue => {
waitForB.setPromise(asynchronousTaskForB(neededValue));
});
});
socket.on('C', data => {
waitForB.then(neededValue => {
asynchronousTaskForC(neededValue);
});
});
socket.on('D', data => {
waitForB.then(neededValue => {
waitForD.setPromise(asynchronousTaskForD(neededValue));
});
});
// Note: I am confused why these functions did not return a Promise before
// They have always done that.
function asynchronousTaskForA() {
return new Promise((resolve, reject) => {
// something
resolve('something needed by B');
});
}
function asynchronousTaskForB(value) {
return new Promise((resolve, reject) => {
// something with value
resolve('something needed by C ... D');
});
}
function asynchronousTaskForC(value) {
return new Promise((resolve, reject) => {
// something with value
resolve();
});
}
function asynchronousTaskForD(value) {
return new Promise((resolve, reject) => {
// something with value
resolve('something needed by E ... F');
});
}
Thank you!