Friday 29 September 2017

Expirable Promises

I'd read some samples of using Promise.race to implement timeouts for Promises (reject the promise if it has not finished after x time). You can see an example here. Looks good, but it's not what had come to my mind when thinking about this issue and not having had the race function into account.

Given that I can not reject and existing promise, I would have to create a new one, that would be rejected if the timeout expires, or resolved if the original promise finishes before the timeout. I call this new promise an "expirable promise". Let's see the code

function createExpirablePromise(pr, expirationTime){
		let nP = new Promise((resolve, reject) => {
			let timeout = setTimeout(() => {
				reject("timed out");
			}, expirationTime);
			pr.then((result) => {
				clearTimeout(timeout);
				resolve(result);
			});
		});
		return nP;
}

If we are given a function that returns a promise we can create a function that returns an expirable promise like this:

//fn is a function that returns a promise
//we return a function that retuns an "expirable promise"
function createExpirableFunction(fn, expirationTime){
	let expirableFn = (val) => {
		let pr = fn(val);
		return createExpirablePromise(pr, expirationTime);
	}
	return expirableFn;
}

With the joyful addition of async/await to the javascript arsenal, we can write a cute sample like this:

//example of a long running async operation
//function that returns a Promise
function formatter1Promisified(st){
	return new Promise((res, rej) => {
		console.log("formatter1 running");
		st = st.toUpperCase();
		setTimeout(() => {
			res(st);
		}, 3000);
	});
}


async function testUsingAsync(){
	let expirationTimes = [1000, 4000];
	for (let i=0; i < expirationTimes.length; i++){
		let timeout = expirationTimes[i];
		try{
			let res = await (createExpirableFunction(formatter1Promisified, timeout))("Hi"); //timeout expires("Hi"); 
			console.log(`succeeded with timeout: ${timeout}, result ${res}`);
			break;
		}
		catch (ex){
			console.log(`failed with timeout: ${timeout}`);
		}
	}
}



testUsingAsync();

No comments:

Post a Comment