I'm trying to implement a timeout for an asynchronous function using a promise and setTimeout. I want to run an asynchronous operation, and if it doesn't complete by a certain amount of time, throw an error. Currently, this is what I have: (some of it found on stackoverflow)
function someOperation(cb) {
setTimeout(function() {
cb(null, 'Done');
}, 2000);
}
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('Operation timed out'));
}, 100);
someOperation(function(err, res) {
if (err) reject(err);
else resolve(res);
});
});
p.then(function(res) {
console.log(res);
}, function(err) {
console.log("Throwing error...")
throw err;
});
But the program doesn't stop when the error is thrown. Would anybody be able to tell me why, and if there is an easier way to do this? I'd be very much appreciative.
EDIT: Now trying to use bluebird for the first time and it is giving someOperationPromised.timeout is not a function. Am I doing this correctly?
var Promise = require("bluebird");
function someOperation(cb) {
setTimeout(function() {
cb('', 'Done');
}, 2000);
}
var someOperationPromised = Promise.promisify(someOperation);
someOperationPromised.timeout(1).then(function (){
console.log("Finished!");
}).catch(Promise.TimeoutError, function (err) {
throw err;
});
Not sure what promise library you're using, if any. May I suggest Bluebird? It's faster than native and has a lot of great features. Among them? Timeout.
From the documentation:
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
fs.readFileAsync("huge-file.txt").timeout(100).then(function(fileContents) {
}).catch(Promise.TimeoutError, function(e) {
console.log("could not read file within 100ms");
});
Edit:
Hey there! I took some time sorting through this, trying to figure out why your edit didn't work. My goal is to prove to you that .timeout() works. Moreover, I would like to provide you with a workable solution you can use moving forward with Bluebird.
Below I include a function I've named takesFourSeconds. It returns a promise that will resolve after 4 seconds. I then call takesFourSeconds twice. The first time I use timeout to force the promise chain to reject if it takes more than 3 seconds. The second time I force it to reject if it takes longer than 5 seconds.
var Promise = require("bluebird");
function takesFourSeconds (){
return new Promise((resolve, reject) => {
setTimeout(function(){
return resolve('hi');
}, 4000);
});
}
takesFourSeconds().timeout(3000).then(function(res) {
console.log(res);
}).catch(Promise.TimeoutError, function(e) {
console.log("promise took longer than 3 seconds");
});
takesFourSeconds().timeout(5000).then(function(res) {
console.log(res);
}).catch(Promise.TimeoutError, function(e) {
console.log("promise took longer than 5 seconds");
});
Note that this returns:
$ node index.js
promise took longer than 3 seconds
hi
As expected.
Small side note:
When creating a function that returns a promise, you don't have to create a new promise for every function you call in a chain of promises. Only the first function.
For example, if I wanted to call another function after takesFourSeconds() I could write it like this:
function myFunc(result){
return result === 'hi' ? resolve('hey there') : reject('hi there');
}
then:
takesFourSeconds()
.then(myFunc) // myFunc will take in the resolved value of takesFourSeconds implicitly
.then(result => console.log(result)
.catch(error => console.log(error);
This should output:
"hey there"
There you have it! Timeouts in Bluebird.js. :)
Related
This question already has answers here:
correct way to handle errors inside a Promise
(3 answers)
Promise constructor with reject call vs throwing error
(4 answers)
Correct Try...Catch Syntax Using Async/Await
(6 answers)
Closed 4 years ago.
I am completely new to Promises and async/await and just reading through tutorials etc., so I expect I may be missing something fundamental.
I've see this code pattern in several places, but I'm thinking maybe it should not be trusted:
async function myFunc() {
try {
var result = await doSomethingAsync();
console.log(result);
}
catch(error) {
console.error(error); // hmm
}
}
myFunc();
Consider the following scenario using the above pattern:
const doSomethingAsync = behaviour => new Promise((resolve, reject) => {
// use setTimeout to simulate e.g. an async webapi callback func
setTimeout(() => {
if(behaviour === "set resolve")
resolve("resolved");
if(behaviour === "set reject")
reject("rejected");
if(behaviour === "set after timeout error")
throw new Error("something went wrong after setTimeout returned");
}, 500);
if(behaviour === "set promise error")
throw new Error("something went wrong in promise");
});
async function myFunc(behaviour) {
try {
// wait for promise to complete
var result = await doSomethingAsync(behaviour);
console.log(result);
}
catch(error) {
console.error("caught:" + error); // will catch reject and promise error,
// but NOT after setTimeout error
}
}
myFunc("set promise error"); // caught:Error: something went wrong in promise
myFunc("set resolve"); // resolved
myFunc("set reject"); // caught:rejected
myFunc("set after timeout error"); // Uncaught Error: something went
// wrong after setTimeout returned
// UHOH!!
So the pattern seems a little misleading as it cannot catch the setTimeout error, whereas people tend to think of catch() as a catch-all.
Of course, changing the setTimeout to have an internal catch will solve the uncaught error problem:
const doSomethingAsync = behaviour => new Promise((resolve, reject) => {
// use setTimeout to simulate e.g. an async webapi call
setTimeout(() => {
try { // ...
}
catch(e) { reject("an error"); }
}, 500);
});
So, my questions are:
As I understand it, Promises are used as a replacement for callbacks, i.e. for wrapping async calls like setTimeout. So should there always be an internal try/catch -> reject pattern implemented inside a Promise? (So that the error can be gracefully handled by the caller). Do e.g. all node libraries work in this way?
I can't see any way for the caller to deal with it by itself.
I find the pattern misleading, wouldn't the pattern be better like this?
async function myFunc(behaviour) {
try {
var result = await doSomethingAsync(behaviour);
.catch(e) { console.log("expected reject happened:" + e) };
}
catch(error) {
console.error("something totally unexpected happened:" + error);
}
}
I just implemented my first function that returns a promise based on another promise in AngularJS, and it worked. But before I decided to just do it, I spent 2 hours reading and trying to understand the concepts behind promises. I thought if I could write a simple piece of code that simulated how promises worked, I would then be able to conceptually understand it instead of being able to use it without really knowing how it works. I couldn't write that code.
So, could someone please illustrate in vanilla JavaScript how promises work?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:
promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:
promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/
When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
For the simplicity to understand about the promises in Javascript.
You can refer below example. Just copy paste in a new php/html file and run.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function test(n){
alert('input:'+n);
var promise = new Promise(function(fulfill, reject) {
/*put your condition here */
if(n) {
fulfill("Inside If! match found");
}
else {
reject(Error("It broke"));
}
});
promise.then(function(result) {
alert(result); // "Inside If! match found"
}, function(err) {
alert(err); // Error: "It broke"
});
}
</script>
</head>
<body>
<input type="button" onclick="test(1);" value="Test"/>
</body>
</html>
Click on Test button,
It will create new promise,
if condition will be true it fulfill the response,
after that promise.then called and based on the fulfill it will print the result.
In case of reject promise.then returns the error message.
Probably the simplest example of promises usage looks like that:
var method1 = (addings = '') => {
return new Promise(resolve => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '') => {
return new Promise(resolve => {
console.log('method2' + addings)
resolve(addings + '_adding2');
});
}
method1().then(method2).then(method1).then(method2);
// result:
// method1
// method2_adding1
// method1_adding1_adding2
// method2_adding1_adding2_adding1
That's basic of basics. Having it, you can experiment with rejects:
var method1 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method2' + addings)
reject();
});
}
var errorMethod = () => {
console.log('errorMethod')
}
method1()
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod);
// result:
// method1*
// method2*_adding1
// errorMethod
// method2*
// errorMethod
// method2*
As we can see, in case of failure error function is fired (which is always the second argument of then) and then next function in chain is fired with no given argument.
For advanced knowledge I invite you here.
please check this simple promise code. this will help you to better understand of promise functionality.
A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved. A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
let myPromise = new Promise((resolve, reject)=>{
if(2==2){
resolve("resolved")
}else{
reject("rejected")
}
});
myPromise.then((message)=>{
document.write(`the promise is ${message}`)
}).catch((message)=>{
document.write(`the promise is ${message}`)
})
check this out
This question already has answers here:
Why does the Promise constructor need an executor?
(2 answers)
Closed 6 years ago.
I wish to return a Promise which is self-resolved at a later time, but it seems that my syntax is invalid, and I'm curious what a better implementation would be. Why is an executor required for the Promise constructor?
promise = new Promise() is invalid because I need to supply a function
function getDetails (someHash) {
var url = "http://somewebsite.com/" + someHash,
promise = new Promise();
makeAjaxRequest(url, function (response) {
promise.resolve(response.data);
});
setTimeout(function () {
promise.reject("timeout");
}, 500);
return promise;
}
function makeAjaxRequest (url, callback) {
var someResponse = {data: "some data"};
setTimeout(function () {
callback(someResponse);
}, 200);
}
Is there a better way to implement this functionality?
Note: If you want to convert a callback API to promises see this question.
Let's start with something that should be said from the get go. An executor is not required in order to design promises. It is entirely possible to design a promises implementation that does something like:
let {promise, resolve, reject} = Promise.get();
If you promise not to tell anyone, I'll even let you in on a little secret - this API even exists from a previous iteration of the spec and in fact even still works in Chrome:
let {promise, resolve, reject} = Promise.defer();
However, it is being removed.
So, why do I need to pass an executor?
I just answered your other question about why an executor is an interesting design. It's throw-safe and it lets you take care of interesting things.
Can I still get the resolve, reject functions? I need those
In my experience, most of the times I needed resolve/reject I didn't actually need them. That said - I did in fact actually need them a couple of times.
The specifiers recognized this and for this reason the executor function is always run synchronously. You can get the .defer interface it just isn't the default:
function defer() {
let resolve, reject, promise = new Promise((res, rej) => {
[resolve, reject] = [res, rej];
});
return {resolve, reject, promise};
}
Again, this is typically not something you want to do but it is entirely possible that you have a justifiable use case which is why it's not the default but completely possible.
Your actual code
I would start with implementing things like timeout and a request as primitives and then compose functions and chain promises:
function delay(ms) {
return new Promise(r => setTimeout(r, ms));
}
function timeout(promise, ms) {
return Promise.race([
promise,
delay(ms).then(x => { throw new Error("timeout"); })
]);
}
function ajax(url) { // note browsers do this natively with `fetch` today
return new Promise((resolve, reject) => { // handle errors!
makeAjaxRequest(url, (result) => {
// if(result.isFailure) reject(...);
if(result.status >= 400) reject(new Error(result.status));
else resolve(result.data);
});
});
}
Now when we promisified the lowest level API surface we can write the above code quite declaratively:
function getDetails (someHash) {
var ajax = makeAjaxRequest("http://somewebsite.com/" + someHash);
return timeout(ajax, 500);
}
You need to pass a function to the Promise constructor (more info), which will get called to provide the resolve and reject functions:
function getDetails (someHash) {
var url = "http://somewebsite.com/" + someHash;
return new Promise(function(resolve, reject) {
makeAjaxRequest(url, function(err, response) {
if (err)
reject(err);
else
resolve(response.data);
});
setTimeout(function () {
reject("timeout");
}, 500);
});
}
function makeAjaxRequest (url, callback) {
var someResponse = {data: "some data"};
setTimeout(function () {
callback(null, someResponse);
}, 200);
}
I've also taken the liberty to make makeAjaxRequest use the standard convention of passing errors as first argument (because I assume that at some point you want to replace the setTimeout() with an actual AJAX request).
I use the following code and there is something that a bit confuse me
if I put in the timeout 1000ms I see that the promise called in the right order
but if I change it to the following
This is step 3
This is step 2
This is step 1
I guess that this happen since when the function is resolved then he proceed to the next function am I correct ? if this is true how can I do this chain that when the first is finished then he proceed to the second etc but without using the promise hell :-)
https://jsfiddle.net/2yym400j/
var step1 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 1");
resolve();
}, ms);
})
}
var step2 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 2");
resolve();
}, ms);
})
};
var step3 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 3");
resolve();
}, ms);
})
};
step1(500)
.then(step2(300))
.then(step3(200))
.catch(function(err) {
console.log(err);
});
Just pass a function instead of the result of the steps.
step1(500)
.then(function() { return step2(300); })
.then(function() { return step3(200); })
.catch(function(err) {
console.log(err);
});
Without this, you are just calling each step without "blocking" for the previous step to resolve.
I know you've already gotten an answer as to why your original code didn't work, but I thought I'd show another way to approach it that is a bit more DRY than what you were doing. You can create a single function that returns a function and then you can use that in the fashion you were using because it returns a function that will be called later which is what .then() wants. So, you can do something like this:
function delay(t, msg) {
return function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log(msg);
resolve();
}, t);
});
}
}
delay(500, "This is step 1")()
.then(delay(300,"This is step 2"))
.then(delay(200, "This is step 3"))
.catch(function(err) {
console.log(err);
});
Working demo here: https://jsfiddle.net/jfriend00/mbpq4g8m/
Daniel White's comment and answer are correct, but I thought an additional explanation might help.
Your original code broke two rules:
then can't take a Promise, but it can take a function that returns a Promise. If you pass in anything except a function, it will be ignored, just like you passed in null instead.
As soon as you call new Promise(someFunction), the someFunction executes asynchronously without waiting for anything. This means you can call new Promise from within a then function, but if you call it early then it won't have the delayed behavior you're expecting.
So given that each call to stepN returns a newly-constructed promise, I've inlined everything that happens synchronously and renamed the results constructAndReturnPromiseN and constructedPromiseThatStepNReturns. That makes your original code looks like this so all the promises happen at once:
constructedPromise1ThatStep1Returns
.then(constructedPromise2ThatStep2Returns) // BAD: Don't pass promises into then.
.then(constructedPromise3ThatStep3Returns) // BAD: Don't pass promises into then.
.catch(function(err) {
console.log(err);
});
...where Daniel White's code does this:
constructedPromise1ThatStep1Returns
// GOOD: The then function returns a promise that is *constructed inside* the function.
.then(function() { return constructAndReturnPromise2(300); })
.then(function() { return constructAndReturnPromise3(200); })
.catch(function(err) {
console.log(err);
});
I am really hoping someone can help me with this issue despite my inability (confidentiality issues) to share too much information. Basically, I wrote this function to retry failed promises:
function retryOnFailure(func) {
return func().then(function(resp) {
return resp
}, function(err) {
return setTimeout(function() {
return retryOnFailure(func)
}, 5000)
}
)}
And then I have this code to utilize it:
function getStuff() {
return $.get('/some/endpoint')
}
retryOnFailure(getStuff).then(function(res) { console.log(res) })
Now the recursive retry function works fine, but my then in the last line of code doesn't fire in the event that an error case is reached in retryOnFailure. I know that the reason is because each recursive call creates a new promise so the promise that I'm listening to in my last line is not the same one that gets resolved, but I'm having difficulty figuring out how to remedy this. I want this function to be a generic retry function and as such don't want to handle the actual success in the method, but I'm not seeing any other way. Any help would be greatly appreciated!
return setTimeout(function() {
return retryOnFailure(func)
}, 5000)
looks like you're trying to do the right thing - return the next result from your .catch callback. However, setTimeout does not return a promise, so retryOnFailure() will be resolved immediately (with the timeout cancellation id).
Instead, you need to make sure that for all asynchronous functions that you use a promise is produced, so let's start by promisifying setTimeout:
function delay(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
});
}
Now we can use that to chain the retry after a delay, and get a promise from it:
function retryOnFailure(func) {
return func().then(null, function(err) {
return delay(5000).then(function() {
return retryOnFailure(func);
});
});
}
Notice that instead of .then(null, …) you can also use .catch(…).
This is the first way that came to mind, there is probably a more elegant solution:
function retryOnFailure(func, onSuccess) {
return func().then(function(resp) {
onSuccess(resp);
}, function(err) {
return setTimeout(function() {
return retryOnFailure(func, onSuccess)
}, 5000)
}
)}
retryOnFailure(getStuff, function(res) { console.log(res) });
The problem is your call to setTimeout, it breaks the flow of your promise. Try something like this instead:
function retryOnFailure(func) {
return new Promise(function(resolve) {
func().then(function(resp) {
resolve(resp);
}).catch(function(err) {
setTimeout(function() {
retryOnFailure(func).then(resolve);
}, 5000)
});
});
};
retryOnFailure(getStuff).then(function(res) { console.log(res) });
Note how I've created a new promise inside the function which never throws an error, but instead will simply attempt to process the func() and recurse itself on failure.
It also may be a good idea to put some kind of retry-limit as well.
Good luck!