I am using a promise to asynchronously connect to an API. The API emits two events: connected
and socketConnected
.
As per my connect()
function, I would like to wait for both of those events to fire.
connect() {
return new Promise((resolve,reject)=>{
this._client.on('connected', resolve);
this._client.on('socketConnected', resolve);
setTimeout(reject, 5000);
}
}
However, you can only resolve once, and I want both events to fire before the promise resolves. How can I set this up so that it behaves that way?
You need to use Promise.all
to create two promises, one for each event, and when both resolve - when the Promise.all
resolves - you can resolve the promise that connect
returns:
connect() {
return new Promise((resolveAll, rejectAll) => {
Promise.all([
new Promise(res1 => this._client.on('connected', res1)),
new Promise(res2 => this._client.on('socketConnected', res2))
]).then(resolveAll);
setTimeout(rejectAll, 5000);
});
}
You might also clear the timeout when the Promise.all
resolves, if you want garbage collection to occur as soon as possible:
connect() {
return new Promise((resolveAll, rejectAll) => {
const rejectTimeout = setTimeout(rejectAll, 5000);
Promise.all([
new Promise(res1 => this._client.on('connected', res1)),
new Promise(res2 => this._client.on('socketConnected', res2))
]).then(() => {
clearTimeout(rejectTimeout);
resolveAll();
});
});
}
I'm a fan of reusable code - if you find yourself wanting to timeout a Promise, then why not write a function to do so
const promiseTimeout = (promise, timeout) => {
let timer;
return Promise.race([
promise,
new Promise((_, reject) => (timer = setTimeout(reject, timeout, promiseTimeout.symbol)))
])
.then(result => (clearTimeout(timer), result));
};
promiseTimeout.symbol = Symbol('timeout');
Now, you can use that anywhere you need to set a time limit for a promise
In this case, as already observed, you'll need two promises for your logic, wrapped in a Promise.all, that get's you one promise that resolves when both promises resolve
ie
const promise = Promise.all([
new Promise(resolve => this._client.on('connected', resolve)),
new Promise(resolve => this._client.on('socketConnected', resolve))
]);
now, combining these two code snippets
const promiseTimeout = (promise, timeout) => {
let timer;
return Promise.race([
promise,
new Promise((_, reject) => (timer = setTimeout(reject, timeout, promiseTimeout.symbol)))
])
.then(result => (clearTimeout(timer), result));
};
promiseTimeout.symbol = Symbol('timeout');
function connect() {
const promise = Promise.all([
new Promise(resolve => this._client.on('connected', resolve)),
new Promise(resolve => this._client.on('socketConnected', resolve))
]);
return promiseTimeout(promise, 5000);
}
// if connect rejects with reason promiseTimeout.symbol, you can be sure it was because of the timeout
Though, the other answer is better in this case, I only offer this answer in case you do find yourself wanting to set a time limit on a promise resolution
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.