Understanding promise.race() usage - javascript

As far as I know, there are two options about promise:
promise.all()
promise.race()
Ok, I know what promise.all() does. It runs promises in parallel, and .then gives you the values if both resolved successfully. Here is an example:
Promise.all([
$.ajax({ url: 'test1.php' }),
$.ajax({ url: 'test2.php' })
])
.then(([res1, res2]) => {
// Both requests resolved
})
.catch(error => {
// Something went wrong
});
But I don't understand what does promise.race() is supposed to do exactly? In other word, what's the difference with not using it? Assume this:
$.ajax({
url: 'test1.php',
async: true,
success: function (data) {
// This request resolved
}
});
$.ajax({
url: 'test2.php',
async: true,
success: function (data) {
// This request resolved
}
});
See? I haven't used promise.race() and it behaves like promise.race(). Anyway, is there any simple and clean example to show me when exactly should I use promise.race() ?

As you see, the race() will return the promise instance which is firstly resolved or rejected:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// Both resolve, but p2 is faster
});
For a scenes to be used, maybe you want to limit the cost time of a request :
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
With the race() you just need to get the returned promise, you needn't care about which one of the promises in the race([]) firstly returned,
However, without the race, just like your example, you need to care about which one will firstly returned, and called the callback in the both success callback.

I've used it for request batching. We had to batch tens of thousands of records into batches for a long running execution. We could do it in parallel, but didn't want the number of pending requests to get out of hand.
Race lets us keep a fixed number of parallel promises running and add one to replace whenever one completes
const _ = require('lodash')
async function batchRequests(options) {
let query = { offset: 0, limit: options.limit };
do {
batch = await model.findAll(query);
query.offset += options.limit;
if (batch.length) {
const promise = doLongRequestForBatch(batch).then(() => {
// Once complete, pop this promise from our array
// so that we know we can add another batch in its place
_.remove(promises, p => p === promise);
});
promises.push(promise);
// Once we hit our concurrency limit, wait for at least one promise to
// resolve before continuing to batch off requests
if (promises.length >= options.concurrentBatches) {
await Promise.race(promises);
}
}
} while (batch.length);
// Wait for remaining batches to finish
return Promise.all(promises);
}
batchRequests({ limit: 100, concurrentBatches: 5 });

It's a piece to build a timeout system, where:
the request/computation may be canceled by another channel
it will still be used later, but we need an interaction now.
For an example of the second, one might show a spinner "instantly" while still defaulting to show real content if it comes in fast enough. Try running the below a few times - note at least some console message comes "instantly". This might normally be attached to perform operations on a UI.
The key to note is - the result of Promise.race is much less important than the side effects (though, this then is a code smell).
// 300 ms _feels_ "instant", and flickers are bad
function getUserInfo(user) {
return new Promise((resolve, reject) => {
// had it at 1500 to be more true-to-life, but 900 is better for testing
setTimeout(() => resolve("user data!"), Math.floor(900*Math.random()));
});
}
function showUserInfo(user) {
return getUserInfo().then(info => {
console.log("user info:", info);
return true;
});
}
function showSpinner() {
console.log("please wait...")
}
function timeout(delay, result) {
return new Promise(resolve => {
setTimeout(() => resolve(result), delay);
});
}
Promise.race([showUserInfo(), timeout(300)]).then(displayed => {
if (!displayed) showSpinner();
});
Inspiration credit to a comment by captainkovalsky.
An example of the first:
function timeout(delay) {
let cancel;
const wait = new Promise(resolve => {
const timer = setTimeout(() => resolve(false), delay);
cancel = () => {
clearTimeout(timer);
resolve(true);
};
});
wait.cancel = cancel;
return wait;
}
function doWork() {
const workFactor = Math.floor(600*Math.random());
const work = timeout(workFactor);
const result = work.then(canceled => {
if (canceled)
console.log('Work canceled');
else
console.log('Work done in', workFactor, 'ms');
return !canceled;
});
result.cancel = work.cancel;
return result;
}
function attemptWork() {
const work = doWork();
return Promise.race([work, timeout(300)])
.then(done => {
if (!done)
work.cancel();
return (done ? 'Work complete!' : 'I gave up');
});
}
attemptWork().then(console.log);
You can see from this one that the timeout's console.log is never executed when the timeout hits first. It should fail/succeed about half/half, for testing convenience.

Here's an easy example to understand the use of promise.race():
Imagine you need to fetch some data from a server and if the data takes too long to load (say 15 seconds) you want to show an error.
You would call promise.race() with two promises, the first being your ajax request and the second being a simple setTimeout(() => resolve("ERROR"), 15000)

Summary:
Promise.race is a JS built in function that accepts an iterable of Promises (e.g. Array) as an argument. This function then asynchronously returns a Promise as soon as one in of the Promises passed in the iterable is either resolved or rejected.
Example 1:
var promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-one'), 500);
});
var promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-two'), 100);
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster than promise 1
});
In this example first an array of Promises is passed in Promise.race. Both of the promises resolve but promise1 resolves faster. Therefore the promise is resolved with the value of promise1, which is the string 'Promise-one'.
Example 2:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('succes'), 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject('err'), 1000);
});
Promise.race([promise1, promise2])
.then((value) => {
console.log(value);
}).catch((value) => {
console.log('error: ' + value);
});
In this second example the second promise rejects faster than the first promise can resolve. Therefore Promise.race will return a rejected promise with the value of 'err' which was the value that Promise2 rejected with.
The key point to understand is that Promice.race takes an iterable of Promises and returns a Promise based on the first resolved or rejected promise in that iterable (with the corresponding resolve() or reject() values).

Let's take an sample workaround of Promise.race like below.
const race = (promises) => {
return new Promise((resolve, reject) => {
return promises.forEach(f => f.then(resolve).catch(reject));
})
};
You can see race function executes all promises, but whomever finishes first will resolve/reject with wrapper Promise.

Related

How to use promise in order to wait for a function to execute

I have an async piece of javascript code that need to execute and then the next statements can be executed
function getEventData() {
return new Promise(resolve => {
eventList.forEach((event) => {
db.collection('Events').doc(event)?.collection('registeredStudents')?.get()
.then((querySnapshot) => {
eventData.push({"id": event, "number": querySnapshot.size})
})
})
resolve();
})
}
getEventData().then(console.log(eventData))
eventList is an array with 17 elements and it list through the database around 17 times, that is inefficient but I had no choice so had to do like that. Anyways in the console I get an empty array logged. How do I solve that. PS: I am new to async javascript and promises.
You can use Promise.all():
function getEventData() {
return new Promise(async (resolve) => {
await Promise.all(
eventList.map(async (event) => {
let querySnapshot = await db.collection('Events').doc(event)?.collection('registeredStudents')?.get()
eventData.push({"id": event, "number": querySnapshot.size})
})
);
resolve();
})
}
getEventData().then(console.log(eventData))
This is a simple demo of how to use promises in a loop. The async operation I am performing is "sleeping" (aka nothing happens until everything has "slept")..
const sleepTimes = [1, 2, 3];
const promises = [];
sleepTimes.forEach(time => {
const promise = new Promise((resolve, reject) => {
return setTimeout(resolve, time * 1000, time * 1000);
});
promises.push(promise);
});
console.log(promises);
Promise.all(promises).then((values) => {
document.body.innerHTML = values;
});
Which would mean your function should look something like:
function getEventData() {
const promises = [];
eventList.forEach((event) => {
// I assume this already returns a promise, so there's no need to wrap it in one
const promise = db.collection("Events").doc(event)?.collection("registeredStudents")?.get();
promises.push(promise);
});
return Promise.all(promises);
}
getEventData().then((values) => console.log(values));
The correct way to deal with your problem is not using new Promise with resolve, yet by using async await.
When you await a promise, it waits for it to resolve and returns the result (not a promise!) before continuing to the next line.
A function awaiting a promise returns a promise when called.
Promise.all combines multiple promises to one, so you can wait for multiple promises to resolve all at once, and have them run at the same time (async).
async function getEventData(eventList) {
try {
const eventData = [];
await Promise.all(eventList.map(async event => {
const querySnapshot = await db.collection('Events').doc(event)?.collection('registeredStudents')?.get();
eventData.push({"id": event, "number": querySnapshot.size});
}));
console.log(eventData)
} catch (exception) {
// error handling
}
}

Promise.all Replacement?

Is there any way where I can call multiple async functions in Javascript, but get response of the call as soon as one completes, unlike Promise.all that waits for all async calls to complete?
What I want is, run async calls in parallel, and get response of a respective call as soon as it gets completed while other calls are still running and then update the react state.
I am already using Promise.all for multiple async calls, but it gives responses when all calls are finished.
You can just iterate over an array of promises and change the state on each promise resolution:
let state = null;
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({p1: 1});
}, 2000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({p2: 2});
}, 1000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({p3: 3});
}, 3000);
});
// Iterate promises
[p1, p2, p3].forEach(p => {
p.then(res => {
state = Object.assign({}, state, res);
console.log(state);
});
});
console.log(state);
You could create your own Promise method for this task:
if (!Promise.each) {
Promise.each = function(promises, callback, error) {
if (promises && Array.isArray(promises)) {
promises.forEach(p => {
p.then(res => {
callback(res);
}, err => {
if (error) {
error(err);
} else {
console.log(err);
}
});
});
}
}
}
// Usage
Promise.each([p1, p2, p3], updateState);
In your question the phrase "than update ... state" is the key. You plan to update the state in such a way that as soon as one promise "completed" the corresponding state is updated. You have been trying something like this
async function f1(){ await Promise.resolve(); }
async funciton f2(){ await Promise.resolve(); }
async function fn(){ await Promise.resolve(); }
async function drvAsync(){
const [r1, r2, rn] = await Promise.all([f1(), f2(), fn()]);
u1(r1);
u2(r2);
un(rn);
}
where f[n] is an async business function, u[n] is a method to deal with the result from it. This schema is not acceptable in your scenario. Perhaps fn completes faster than others and you want to update N-th state earlier.
My recommendation is use no synchronization primitives at all. Instead you should deal with the results separately.
function drv(){
f1().then((r1)=>u1(r1)).catch((e)=>er(e));
f2().then((r2)=>u2(r2)).catch((e)=>er(e));
fn().then((rn)=>un(rn)).catch((e)=>er(e));;
}
This schema will call each update (u[n]) method without waiting results from others.
This is what Promise.race is for:
The Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.
For instance:
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function main() {
const promises = [
sleep(1000).then(() => "world"),
sleep(100).then(() => "hello"),
];
const promisesWithIndices = promises.map((p, index) =>
p.then((result) => ({result, index}))
);
while (promisesWithIndices.length > 0) {
const {result, index} = await Promise.race(promisesWithIndices);
console.log("%s -> %s", index, result);
promisesWithIndices.splice(index, 1);
}
}
main(); // prints "1 -> hello"; then prints "0 -> world" after a while
As long as you don't use async/await you can do the calls in parallel. Note that browsers have connection limit for network requests so if you execute for example 100 calls it will not be parallel but rather be queued.
You need a callback to execute when the promise resolved. If this callback is the same for all functions than just loop all calls, create the promise and resolve with the same function.
function resolved(data) {
// ...
}
const promise1 = new Promise(function(resolve, reject) {
resolve('Success!');
}).then(resolved);
const promise2 = new Promise(function(resolve, reject) {
resolve('Success!');
}).then(resolved);

Setting a timeout for each promise within a promise.all

I am able to successfully perform a Promise.all, and gracefully handle resolves and rejects. However, some promises complete within a few milliseconds, some can/could take a while.
I want to be able to set a timeout for each promise within the Promise.all, so it can attempt to take a maximum of say 5seconds.
getData() {
var that = this;
var tableUrls = ['http://table-one.com','http://table-two.com'];
var spoonUrls = ['http://spoon-one.com','http://spoon-two.com'];
var tablePromises = that.createPromise(tableUrls);
var spoonPromises = that.createPromise(spoonUrls);
var responses = {};
var getTableData = () => {
var promise = new Promise((resolve, reject) => {
Promise.all(tablePromises.map(that.rejectResolveHandle))
.then((results) => {
responses.tables = results.filter(x => x.status === 'resolved');
resolve(responses);
});
});
return promise;
};
var getSpoonData = () => {
var promise = new Promise((resolve, reject) => {
Promise.all(spoonPromises.map(that.rejectResolveHandle))
.then((results) => {
responses.tables = results.filter(x => x.status === 'resolved');
resolve(responses);
});
});
return promise;
};
return getTableData()
.then(getSpoonData);
}
rejectResolveHandle() {
return promise.then(function(v) {
return {v:v, status: "resolved"};
}, function(e) {
return {e:e, status: "rejected"};
});
}
createPromise(links) {
var promises = [];
angular.forEach(links, function (link) {
var promise = that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
promises.push(promise);
});
return promises;
}
I have tried adding a timeout to createPromise(), however this does not seem to work. Setting a timeout to 300ms, some requests continue for 4+seconds:
createPromise(links) {
var promises = [];
angular.forEach(links, function (link) {
var promise = that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
promise = new Promise((resolve) => {
setTimeout(() => {
resolve(promise);
}, 300);
});
promises.push(promise);
});
return promises;
}
I have access to Bluebird if it will makes things easier?
Here's a scheme that creates a Promise.raceAll() function that works kind of like a combination of Promise.all() and Promise.race() where the promises all have a timeout time and value so that if the promise doesn't resolve before that time, it will be short circuited to resolve with the passed in value. This essentially puts each promise into a Promise.race() with a timer. If the timer wins, the promise is resolved with the default value. If the original promise wins, it's resolved with the actual promise result. We use Promise.race() to resolve with the first one to finish (the timeout or the original promise). This is a classic use for Promise.race() (in fact the only practical use I've ever really used it for).
A classic example would be to get me all the results you can in the next 15 seconds. Any results that take longer than 15 seconds, just return null for them and don't wait for them. Here's the code to make this concept work:
Promise.delay = function(t, val) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, val), t);
});
}
Promise.raceAll = function(promises, timeoutTime, timeoutVal) {
return Promise.all(promises.map(p => {
return Promise.race([p, Promise.delay(timeoutTime, timeoutVal)])
}));
}
So, you use Promise.raceAll() like Promise.all() in that you pass it an array of promises, but you also pass it a timeoutTime and a timeoutVal. The timeoutTime is the how long to wait before timing out the promises. The timeoutVal is what to put in the results array for any promise that timed out (often it will be something like null that you can easily recognize as a non-real result).
I'm not sure I entirely what you are doing in your specific code, but here's your links code using the above:
Promise.raceAll(links.map(link => {
return that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
});
}), 5000, null).then(results => {
// process results here
// any timed out values will be null
// you can filter out the timed out results
let final = results.filter(item => !!item);
}).catch(err => {
// process any errors here
});
Or, if you want to make sure Promise.raceAll() gets all results, even if some promises reject, you can add a .catch() handler to each promise:
Promise.raceAll(links.map(link => {
return that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
}).catch(err => {
// don't let Promise.all() see a reject so it gets all results
return null;
});
}), 5000, null).then(results => {
// process results here
// any timed out values will be null
// you can filter out the timed out or rejected results
let final = results.filter(item => !!item);
}).catch(err => {
// process any errors here
});
Your attempt just overwrites promise with the timeout promise, meaning that the HTTP promise will be completely ignored.
This is one of the relatively few places where you'd actually use new Promise*: Create a promise, resolve or reject it based on the HTTP call, and reject it (or resolve it, but that seems odd) on timeout:
createPromise(links) {
return Promise.all(links.map(function(link) {
return new Promise((resolve, reject) => {
that._$http({
method: 'GET',
url: link + '/my/end/point',
responseType: 'json'
})
.then(resolve)
.catch(reject);
setTimeout(() => {
reject(/*...relevant value here...*/); // Seems like reject to me,
// but you could use resolve
// if you prefer
}, 300);
});
}));
}
(That uses map on the assumption that links is an array.)
Note that once resolve or reject has been called for a promise, subsequent calls to either are completely ignored (without error or warning). (If that weren't true, we'd want a flag above to track whether we'd settled the promise already.)
* (Unless you have a promise-enabled version of setTimeout. If you do, you'd use Promise.race like jfriend00 did in their answer.)
One solution might be to convert each promise in an argument array for Promise.all into a timed out promise (say using .map). The timeout function could resolve or reject a supplied argument promise depending on application needs.
Using a unique value to resolve a promise after timeout allows it to be identified in the result array supplied to a Promise.all.then( handler)
This example looks out converting a promise into a resolved promise using a helper function timedPromise. Mapping a promise array to an array of timed out promises is not included.
const timedOutValue = new Error( "promise timeout"); // unique value
const timedPromise = (promise, timeout) => {
return new Promise( (resolve, reject) => {
promise.then(resolve, reject);
setTimeout( resolve, timeout, timedOutValue); // could have used reject
});
};
var pendingPromise = new Promise( (resolve,reject) => null); // never settles
timedPromise(pendingPromise)
.then(
data=> console.log( "pendingPromise resolved with %s",
data === timedOutValue ? "timedOutValue" : data),
reason=> console.log( "pendingPromise rejected with %s",
reason === timedOutValue ? "timedOutValue" : reason)
);

What are some typical use-cases for `Promise.race()`? [duplicate]

As far as I know, there are two options about promise:
promise.all()
promise.race()
Ok, I know what promise.all() does. It runs promises in parallel, and .then gives you the values if both resolved successfully. Here is an example:
Promise.all([
$.ajax({ url: 'test1.php' }),
$.ajax({ url: 'test2.php' })
])
.then(([res1, res2]) => {
// Both requests resolved
})
.catch(error => {
// Something went wrong
});
But I don't understand what does promise.race() is supposed to do exactly? In other word, what's the difference with not using it? Assume this:
$.ajax({
url: 'test1.php',
async: true,
success: function (data) {
// This request resolved
}
});
$.ajax({
url: 'test2.php',
async: true,
success: function (data) {
// This request resolved
}
});
See? I haven't used promise.race() and it behaves like promise.race(). Anyway, is there any simple and clean example to show me when exactly should I use promise.race() ?
As you see, the race() will return the promise instance which is firstly resolved or rejected:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// Both resolve, but p2 is faster
});
For a scenes to be used, maybe you want to limit the cost time of a request :
var p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
With the race() you just need to get the returned promise, you needn't care about which one of the promises in the race([]) firstly returned,
However, without the race, just like your example, you need to care about which one will firstly returned, and called the callback in the both success callback.
I've used it for request batching. We had to batch tens of thousands of records into batches for a long running execution. We could do it in parallel, but didn't want the number of pending requests to get out of hand.
Race lets us keep a fixed number of parallel promises running and add one to replace whenever one completes
const _ = require('lodash')
async function batchRequests(options) {
let query = { offset: 0, limit: options.limit };
do {
batch = await model.findAll(query);
query.offset += options.limit;
if (batch.length) {
const promise = doLongRequestForBatch(batch).then(() => {
// Once complete, pop this promise from our array
// so that we know we can add another batch in its place
_.remove(promises, p => p === promise);
});
promises.push(promise);
// Once we hit our concurrency limit, wait for at least one promise to
// resolve before continuing to batch off requests
if (promises.length >= options.concurrentBatches) {
await Promise.race(promises);
}
}
} while (batch.length);
// Wait for remaining batches to finish
return Promise.all(promises);
}
batchRequests({ limit: 100, concurrentBatches: 5 });
It's a piece to build a timeout system, where:
the request/computation may be canceled by another channel
it will still be used later, but we need an interaction now.
For an example of the second, one might show a spinner "instantly" while still defaulting to show real content if it comes in fast enough. Try running the below a few times - note at least some console message comes "instantly". This might normally be attached to perform operations on a UI.
The key to note is - the result of Promise.race is much less important than the side effects (though, this then is a code smell).
// 300 ms _feels_ "instant", and flickers are bad
function getUserInfo(user) {
return new Promise((resolve, reject) => {
// had it at 1500 to be more true-to-life, but 900 is better for testing
setTimeout(() => resolve("user data!"), Math.floor(900*Math.random()));
});
}
function showUserInfo(user) {
return getUserInfo().then(info => {
console.log("user info:", info);
return true;
});
}
function showSpinner() {
console.log("please wait...")
}
function timeout(delay, result) {
return new Promise(resolve => {
setTimeout(() => resolve(result), delay);
});
}
Promise.race([showUserInfo(), timeout(300)]).then(displayed => {
if (!displayed) showSpinner();
});
Inspiration credit to a comment by captainkovalsky.
An example of the first:
function timeout(delay) {
let cancel;
const wait = new Promise(resolve => {
const timer = setTimeout(() => resolve(false), delay);
cancel = () => {
clearTimeout(timer);
resolve(true);
};
});
wait.cancel = cancel;
return wait;
}
function doWork() {
const workFactor = Math.floor(600*Math.random());
const work = timeout(workFactor);
const result = work.then(canceled => {
if (canceled)
console.log('Work canceled');
else
console.log('Work done in', workFactor, 'ms');
return !canceled;
});
result.cancel = work.cancel;
return result;
}
function attemptWork() {
const work = doWork();
return Promise.race([work, timeout(300)])
.then(done => {
if (!done)
work.cancel();
return (done ? 'Work complete!' : 'I gave up');
});
}
attemptWork().then(console.log);
You can see from this one that the timeout's console.log is never executed when the timeout hits first. It should fail/succeed about half/half, for testing convenience.
Here's an easy example to understand the use of promise.race():
Imagine you need to fetch some data from a server and if the data takes too long to load (say 15 seconds) you want to show an error.
You would call promise.race() with two promises, the first being your ajax request and the second being a simple setTimeout(() => resolve("ERROR"), 15000)
Summary:
Promise.race is a JS built in function that accepts an iterable of Promises (e.g. Array) as an argument. This function then asynchronously returns a Promise as soon as one in of the Promises passed in the iterable is either resolved or rejected.
Example 1:
var promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-one'), 500);
});
var promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise-two'), 100);
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster than promise 1
});
In this example first an array of Promises is passed in Promise.race. Both of the promises resolve but promise1 resolves faster. Therefore the promise is resolved with the value of promise1, which is the string 'Promise-one'.
Example 2:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('succes'), 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject('err'), 1000);
});
Promise.race([promise1, promise2])
.then((value) => {
console.log(value);
}).catch((value) => {
console.log('error: ' + value);
});
In this second example the second promise rejects faster than the first promise can resolve. Therefore Promise.race will return a rejected promise with the value of 'err' which was the value that Promise2 rejected with.
The key point to understand is that Promice.race takes an iterable of Promises and returns a Promise based on the first resolved or rejected promise in that iterable (with the corresponding resolve() or reject() values).
Let's take an sample workaround of Promise.race like below.
const race = (promises) => {
return new Promise((resolve, reject) => {
return promises.forEach(f => f.then(resolve).catch(reject));
})
};
You can see race function executes all promises, but whomever finishes first will resolve/reject with wrapper Promise.

Is this possible to limit javascript function executing time?

I got a long javascript function, it may process a few second. But I would like to limit the javascript executing time, if it is longer than X second, whatever the executing result, the function will be killed. Is this possible to implement that in JS? Thanks.
I used promises to achieve this. I just started 2 promises: first is my function to be executed wrapper in promise, second is timeout promise - when operation consider to be failed and use reject in it.
Using Promise.race I just wait what action is completed first. If second - reject occurs, if first - my code completes successfully.
Here is example:
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, "long_execution");
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "ok");
});
var p3 = new Promise((resolve, reject) => {
setTimeout(reject, 1000, "reject");
});
Promise.race([p1, p3]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
Promise.race([p2, p3]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
JavaScript is a single threaded, so one need to use async mechanism to achieve what you're trying to do.
One way of doing this with a single promise with TimeOut. If timeout happens then you promise is Rejected and if not the Promise is resolved.
A Sample code may look something like
var PTest = function () {
return new Promise(function (resolve, reject) {
setTimeout(function() {
reject();
}, 2000)
// Lines of Code
resolve();
});
}
var myfunc = PTest();
myfunc.then(function () {
console.log("Promise Resolved");
}).catch(function () {
console.log("Promise Rejected");
});

Categories

Resources