Cancel JavaScript Promise - javascript

I am trying to cancel a promise as given below:
function example(cancel = Promise.reject()) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve('jack-jack'), 5000);
cancel.then((res) => {
clearTimeout(timer);
reject('cancelled');
}, ()=>{})
});
}
var cancel=Promise.reject();
example(cancel).then((res) => console.log('res handled:' + res)).catch((err) => console.log('err handled:' + err));
console.log('attempting cancellation of promise');
cancel=Promise.resolve();
However I am not able to cancel it. What am I doing wrong over here?

In your code you pass already a complete (rejected) Promise to the function. And cancel=Promise.resolve(); after attempting cancellation of promise won't have any effect to promise that was passed to example because you just create a new resolved Promise.
If you want to cancel a running process then you might want choose such a solution:
function example(helper) {
return new Promise((resolve, reject) => {
helper.cancel = function() {
clearTimeout(timer)
reject('cancelled');
}
const timer = setTimeout(() => resolve('jack-jack'), 5000);
});
}
var helper = {};
example(helper).then((res) => console.log('res handled:' + res)).catch((err) => console.log('err handled:' + err));
console.log('attempting cancellation of promise');
helper.cancel()

You’ve assigned a rejected promise to a variable, passed the rejected promise into your function, and assigned a resolved promise to the variable. The two values the variable takes on are unrelated, and you can’t change the state of a settled promise.
Pass in a promise you can resolve:
let cancel;
let cancelPromise = new Promise((resolve) => {
cancel = resolve;
});
example(cancelPromise).then(…).catch(…);
console.log('attempting cancellation of promise');
cancel();
function example(cancel = Promise.reject()) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve('jack-jack'), 5000);
cancel.then((res) => {
clearTimeout(timer);
reject('cancelled');
}, ()=>{})
});
}
let cancel;
let cancelPromise = new Promise((resolve) => {
cancel = resolve;
});
example(cancelPromise)
.then((res) => console.log('res handled:' + res))
.catch((err) => console.log('err handled:' + err));
console.log('attempting cancellation of promise');
cancel();

Since the cancel is set to reject, the then part
cancel.then((res) => { //you cannot use then for reject, as reject cannot be resolved.
clearTimeout(timer);
reject('cancelled');
}, ()=>{})
will never gets executed hence you have to resolve it, not reject it
function example(cancel = Promise.reject()) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve('jack-jack'), 5000);
cancel.then((res) => { //you cannot use then for reject
clearTimeout(timer);
reject('cancelled');
}, ()=>{})
});
}
var cancel = Promise.resolve(); // just change to resolve
example(cancel).then((res) => console.log('res handled:' + res)).catch((err) => console.log('err handled:' + err));
console.log('attempting cancellation of promise');
cancel=Promise.resolve(); // this will have no effect as you have already passed a reject

Because you are passing rejected promise. Pass the resolved promise if you want cancel.then() block to run.
function example(cancel = Promise.resolve()) {
return new Promise((resolve, reject) => {
console.log(cancel);
const timer = setTimeout(() => {
resolve('jack-jack'), 5000
});
cancel.then((res) => {
console.log('CANCELLED');
clearTimeout(timer);
reject('cancelled');
}, () => {})
});
}
var cancel = Promise.resolve();
example(cancel).then((res) => console.log('res handled:' + res)).catch((err) => console.log('err handled:' + err));
console.log('attempting cancellation of promise');
cancel = Promise.resolve();

Related

Perform an action after a promise.then callback

I'm trying to encapsulate some intialization / clean up code in a single Promise. What I want if to execute some code, execute the then and then execute some more code. This is what I came up with:
function initialize() {
let callback;
console.log('intialization');
const promise = new Promise(resolve => callback = resolve);
new Promise(async () => {
await callback();
await promise;
console.log('cleanup');
});
return promise;
}
initialize().then(() => console.log('execute then'));
which gives me the following output in the terminal:
initialization
execute then
cleanup
- Promise {<fulfilled>: undefined}
All good so far. However, when we make the callback async, it no longer works.
initialize().then(
async () => {
await new Promise(resolve => {
setTimeout(
() => {
console.log('execute then');
resolve();
},
10000
)
})
}
);
gives me this output:
initialization
cleanup
- Promise {<pending>}
execute then
I would have expected it to look like this:
initialization
- Promise {<pending>}
execute then
cleanup
How can I fix this? Is this even possible at all?
You can accept a callback that defines an asynchronous operation. Then it can be inserted into the middle of an promise chain:
const delayMessage = (message, ms) =>
new Promise(resolve => setTimeout(() => {
console.log(message);
resolve();
}, ms));
async function somethingAsync() {
console.log('intialization');
}
function initialize(callback) {
return somethingAsync()
.then(callback)
.then(() => {
console.log('cleanup');
});
}
const middleOfProcess = () => delayMessage('execute then', 2000);
initialize(middleOfProcess);
It works even if there are multiple async steps to do in between, since you can simply chain them together:
const delayMessage = (message, ms) =>
new Promise(resolve => setTimeout(() => {
console.log(message);
resolve();
}, ms));
async function somethingAsync() {
console.log('intialization');
}
function initialize(callback) {
return somethingAsync()
.then(callback)
.then(() => {
console.log('cleanup');
});
}
const middleOfProcess = () => delayMessage('execute then1', 2000)
.then(() => delayMessage('execute then2', 2000))
.then(() => delayMessage('execute then3', 2000));
initialize(middleOfProcess);
The same can be done using async/await syntax:
const delayMessage = (message, ms) =>
new Promise(resolve => setTimeout(() => {
console.log(message);
resolve();
}, ms));
async function somethingAsync() {
console.log('intialization');
}
async function initialize(callback) {
await somethingAsync();
await callback();
console.log('cleanup');
}
const middleOfProcess = async () => {
await delayMessage('execute then1', 2000);
await delayMessage('execute then2', 2000);
await delayMessage('execute then3', 2000);
};
initialize(middleOfProcess);

How do i write promises in javascript

im trying to write a promise but seems to be missing something. here is my code:
const myPromise = new Promise(() => {
setTimeout(() => {
console.log("getting here");
return setinputs({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then(() => {
console.log("getting here too");
firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
if i run the program, the first part of the promise is executing but all .then() functions arent executing. how do i fix this?
In this scheme, the promise callback has one (resolve) or two (resolve,reject) arguments.
let p = new Promise((resolve, reject)=> {
//do something
//resolve the promise:
if (result === "ok") {
resolve(3);
}
else {
reject("Something is wrong");
}
});
p.then(res => {
console.log(res); // "3"
}).catch(err => {
console.error(err); //"Something is wrrong
});
Of course, nowadays you can use async + await in a lot of cases.
You need to resolve the promise, using resolve() and also return the promise from firebase so the next .then in the chain works properly.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("getting here");
// You have to call resolve for all `.then` methods to be triggered
resolve({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then((inputs) => {
console.log("getting here too");
// You have to return a promise in a .then function for the next .then to work properly
return firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});

How to set a time limit to a method in NodeJs?

I have a use case, where I am doing an external API call from my code,
The response of the external API is required by my code further on
I am bumping into a scenario, where the external API call at times takes far too long to return a response,
casing my code to break, being a serverless function
So I want to set a time limit to the external API call,
Where if I don't get any response from it within 3 secs, I wish the code to gracefully stop the further process
Following is a pseudo-code of what I am trying to do, but couldn't figure out the logic -
let test = async () => {
let externalCallResponse = '';
await setTimeout(function(){
//this call sometimes takes for ever to respond, but I want to limit just 3secs to it
externalCallResponse = await externalCall();
}, 3000);
if(externalCallResponse != ''){
return true;
}
else{
return false;
}
}
test();
Reference -
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property
I'm using AWS SSM's getParameters method
You cannot await setTimeout as it doesn't returns a Promise.
You could implement a function that returns a Promise which is fulfilled after 3 seconds.
function timeout(seconds) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1000)
});
}
You can await the above function in your code passing the number of seconds you want to wait for
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await externalCall();
}, 0);
await timeout(3); // wait for 3 seconds
if(externalCallResponse != '') return true;
else return false;
}
Following code snippet demonstrates the usage of timeout function written above. It mocks a api request that returns a response after 4 seconds.
function timeout(seconds) {
return new Promise(resolve => {
setTimeout(resolve, seconds * 1000);
});
}
function apiRequest() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 4000);
});
}
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await apiRequest();
}, 0);
await timeout(3); // wait for 3 seconds
if (externalCallResponse != '') return true;
else return false;
};
test()
.then(res => console.log(res))
.catch(err => console.log(err.message));
you can use something like this, I created a function that return a promise then I used this promise.
let test = async () => {
return promiseTimeout()
}
const promiseTimeout = () => {
return new Promise(async (resolve, reject) => {
setTimeout(function () {
let externalCallResponse=""
externalCallResponse = await externalCall();
if (externalCallResponse != '') {
return resolve(true);
}
else {
return resolve(false);
}
}, 3000);
})
}
test().then(result=>{
console.log(result);
});
You could do something like this:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
timeout(() => doStuff(), 3000)
.then(() => console.log('worked'))
.catch(() => console.log('timed out'));
Tests:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
const doStuffShort = async () => { // Runs for 1 second
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
const doStuffLong = async () => { // Runs for 5 seconds
return new Promise((resolve) => setTimeout(() => resolve(), 5000));
}
timeout(() => doStuffShort(), 3000)
.then(() => console.log('1 worked'))
.catch(() => console.log('1 timed out'));
timeout(() => doStuffLong(), 3000)
.then(() => console.log('2 worked'))
.catch(() => console.log('2 timed out'));

What is the proper way to use Promise.reject with javascript

I have this following piece of code
new Promise((resolve, reject) => {
resolve(apiRequest(data))
reject(console.log('Error'))
}).then(response)
Both methods (resolve and reject) are being fired but I want to call reject only when something goes wrong.
How can I throw an error if something goes wrong on that case?
I checked that but it seems like I can not use an If statement to do that check.
new Promise((resolve, reject) => {
const printResult = apiRequest(data)
console.log(printResult) //Outputs Promise {<pending>}
resolve(printResult) //Then it works
reject(console.log('Error'))
}).then(response)
What would be the correct approach to reject a promise?
The easiest way would be with an if condition. i.e
new Promise((resolve, reject) => {
// do something...
if(somethingGoodHappened) {
resolve(data)
} else {
reject(error)
}
})
But usually when dealing with async requests, the thing you are calling will often be returning a promise, so you can attach the then and catch callbacks there.
apiRequest(data)
.then((result) => {
// all good
})
.catch((err) => {
console.log(err)
})
const mock_api = () => new Promise((res, rej) => {
const number = Math.floor((Math.random() * 100) + 1);
setTimeout(() => {
if (number%2==0) return res('randomly RESOLVED')
return rej('randomly REJECTED')
}, 2000)
})
const async_promise = () => new Promise(async (resolve, reject) => {
try {
const resolvedPromise = await mock_api()
resolve(resolvedPromise)
} catch (e) {
reject(e)
}
})
const classicPromise = () => new Promise((resolve, reject) => {
mock_api()
.then(resolve)
.catch(reject)
})
const makeAsyncRequest = async () => {
try {
const data = await async_promise()
console.log('ASYNC AWAIT RESOLVE', data)
} catch (e) {
console.log('ASYNC AWAIT ERR', e)
}
}
makeAsyncRequest()
classicPromise()
.then(r => console.log('PROMISE CHAIN RESOLVE', r))
.catch(e => console.log('PROMISE CHAIN ERR', e))
Because of you resolve before reject so it cannot run into reject,
You can use:
if (printResult) {
resolve(printResult)
} else {
reject(console.log('Error'))
}
You can catch exceptions and return them as rejected Promises
function asyncFunc() {
try {
doSomethingSync();
return doSomethingAsync()
.then(result => {
···
});
} catch (err) {
return Promise.reject(err);
}
}
Always check for err if there is any err return a promise (example below)
// Return new promise
return new Promise(function(resolve, reject) {
// Do async job
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})

using response from promise later on in chain [duplicate]

This question already has answers here:
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 6 years ago.
I've promise chain which the response in the first chain should be used later on in the chain (in 4 & 6) places, I use some global variable to handle it but this is not the right way ,there is a better way to achieve this with promise?
This is some illustration for the issue...
var step1 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 1");
resolve(20);
}, ms);
})
}
var step2 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 2");
resolve();
}, ms);
})
};
var step3 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 3");
resolve();
}, ms);
})
};
var step4 = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("Step 4, run : " + ms );
resolve();
}, ms);
})
};
var globalVar = null;
//Promise chain
step1(500)
.then((res) => {
//Here I keep the response in global variable to use later on
globalVar = res;
log(res);
return step2(300);
}).then(() => {
return step3(200);
}).then(() =>{
//Here I need to use the res from the first promise
var lclvar = globalVar +200 ;
return step4(lclvar);
}).catch((err) => {
log(err);
});
I found this but this is not helping in this case(at least didn't able to handle it)
How do I access previous promise results in a .then() chain?
You could just nest the step2, step3, etc calls inside the first handler, then res would be available to them all
step1(500).then((res) => {
log(res);
return step2(300)
.then(() => step3(200))
.then(() => step4(res + 200));
}).catch((err) => {
log(err);
});
If you really wan to chain this actually words. the idea is a bus parameter traveling along the way.It's created in the first promise as a closure.
you can run this code:
log=console.log
var step1 = (ms) => {
var Buss={p1:20};
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 1");
resolve(Buss);
}, ms);
})
}
var step2 = (ms,bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 2");
resolve(bus);
}, ms);
})
};
var step3 = (ms,bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("This is step 3");
resolve(bus);
}, ms);
})
};
var step4 = (bus) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
log("Step 4, run : " + bus.p1 );
log("bus arrives:",bus);
resolve(bus);
}, bus.p1);
})
};
//Promise chain
step1(500)
.then((res) => {
//Here I keep the response in global variable to use later on
//globalVar = res;
log(res);
return step2(300,res);
}).then((res) => {
return step3(200,res);
}).then((res) =>{
//Here I need to use the res from the first promise
//var lclvar = globalVar +200 ;
res.p1+=200;
return step4(res);
}).catch((err) => {
log(err);
});

Categories

Resources