Why doesn't the method `shouldNotResolve` catch the rejected promise? - javascript

I would expect that a.shouldNotResolve() would 'catch' the rejected promise in a.cancelOrder, and return 'expected this to catch', but instead it resolves, returning 'promise resolved anyway'.
const a = {
cancelOrder: function(){
return Promise.reject('something broke')
.then((x) => {
return x;
})
.catch((e) => {
console.log('this caught the error', e);
});
},
shouldNotResolve: function() {
return this.cancelOrder()
.then(() => {
console.log('promise resolved anyway');
})
.catch(() => {
console.log('expected this to catch');
});
}
}
a.shouldNotResolve(); // "promise resolved anyway"
Why does a.cancelOrder reject, but a.shouldNotResolve resolves anyway?
Thank you.

Because you catch this error inside
cancelOrder: function(){
return Promise.reject('something broke')
.then((x) => {
return x;
})
.catch((e) => { // <-- this catches all errors
console.log('this caught the error', e);
});
},
catch is literally like try-catch for promises. If you already caught an exception outer one wont catch.
try {
try {
throw new Error('Failed')
} catch(e) { // first catch
console.log('inner', e.message)
}
} catch(e) { // second catch
console.log('outer', e.message)
}
As #robertklep suggests you might want to re-throw
cancelOrder: function(){
return Promise.reject('something broke')
.then((x) => {
return x;
})
.catch((e) => { // <-- this catches all errors
console.log('this caught the error', e);
return Promise.reject(e) // re-reject
});
},
const rejected1 = Promise.reject(1)
const resolved = rejected1
.catch(x => console.log(x))
.then(() => console.log('resolved'))
const rejected2 = rejected1.catch(() => {
console.log('caught but rethrow')
return Promise.reject(2)
})
rejected2.catch(x => console.log(x))

Because it's already caught ("catched"?) earlier in the chain, as seen in the cancelOrder function. If you want to catch it there but still pass the rejection down the chain you need to throw it again:
cancelOrder: function(){
return Promise.reject('something broke')
.then((x) => {
return x;
})
.catch((e) => {
console.log('this caught the error', e);
throw e;
});
}

Write the catch in cancelOrder outside the promise flow, so it doesn't put the promise back in success state.
const a = {
cancelOrder: function(){
const result = Promise.reject('something broke')
.then((x) => {
return x;
});
result.catch((e) => {
console.log('this caught the error', e);
});
return result;
},
shouldNotResolve: function() {
return this.cancelOrder()
.then(() => {
console.log('promise resolved anyway');
})
.catch(() => {
console.log('expected this to catch');
});
}
}
As mentioned in another answer, another option, if you want to put the catch in the promise flow, is to re-throw the error.
You might also consider writing an interceptor which does this for you:
function doCatch(fn) {
return function(reason) {
fn(reason);
throw reason;
});
}
Now you can write
cancelOrder: function(){
return Promise.reject('something broke')
.then((x) => {
return x;
})
.catch(doCatch(err => console.err("this caught the error", e)));
}
By the way, .then((x) => { return x; }) is a no-op.

Related

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);
});

Calling reject multiple times in the chain not being caught

I was expermenting with promises and error handling, but I cannot explain the behaviour of a piece of code. Promise.reject is called twice, the first is handled perfectly but the latter is not being caughed at all.
const a = Promise.resolve('test');
a
.then(item => Promise.reject('promise reject 1'))
.then(
(a) => {
console.log(a); // value: test
},
(err) => {
console.log(err); // value: promise reject 1
}
).then((a) => {
console.log('continue1'); // being called
Promise.reject('promise reject 2') // called but not caught
},
(err) => {
console.log(err); // never being called
})
.catch((err) => {
console.log(err); // never being called
});
I expected the catch to catch the error introduced at line 14 (Promise.reject('promise reject 2')), but the catch handler is never called
Promise.reject() just makes a rejected promise object. Your chain doesn't know anything about it unless you return it. If you return it, the next catch will catch it:
const a = Promise.resolve('test');
a
.then(item => Promise.reject('promise reject 1'))
.then(
(a) => {
console.log(a); // value: test
},
(err) => {
console.log(err); // value: promise reject 1
}
).then((a) => {
console.log('continue1'); // being called
return Promise.reject('promise reject 2') // << ---- Return me!
},
(err) => {
console.log(err); // never being called
})
.catch((err) => {
console.log("from catch:",err); // caught!
})
You can also throw in then():
const a = Promise.resolve('test');
a
.then(item => Promise.reject('promise reject 1'))
.then(
a => {
console.log(a); // value: test
},
err => {
console.log(err); // value: promise reject 1
})
.then(
a => {
console.log('continue1'); // being called
throw(new Error('promise reject 2')) // <-- no return required
},
err => {
console.log(err); // never being called
})
.catch(err => {
console.log("from catch:",err.message); // caught!
})

Promises can't run code after resolve/reject

I have async function in async function. In the second I must wait when promises resolve or reject and after run other code below. But if promise reject my code stopping and no run other functions. How I can fix it?
await axios.all(promises).then(res => {
axios.patch("/url", { foo: bar }).then(async () => {
const promises2 = arr.map(item => {
return axios.post("/url-2", item)
});
await Promise.all(promises2)
.then(() => console.log("resolved")) //this not calling ever
.catch(() => console.log("failed")) //this not calling ever
console.log("This console log ever not working")
})
})
Promises aren't chained properly, axios.patch(...) promise isn't returned. await is syntactic sugar for then and catch, its purpose is to get rid of nested functions where possible. It should be:
const res = await axios.all(promises)
await axios.patch("/url", { foo: bar })
const promises2 = arr.map(item => {
return axios.post("/url-2", item)
});
try {
await Promise.all(promises2)
console.log("resolved"))
} catch (err) {
console.log("failed");
}
The order of your code is wrong. Of course if the first promise is rejected, then the rest will not be called.
Try rewriting your code this way:
let res = await axios.all(promises).catch(() => { console.log("failed"); return false; });
if (!res) {
// Do something when rejected
....
}
// Call the 2nd promise
let res2 = await axios.path("/url", {foo: bar}).catch(() => {console.log("failed 2"); return false; });
if (!res2) {
// Do something when the 2nd promise is rejected
...
}
// Call your last promise
let res3 = await Promise.all(promises2).catch(() => {console.log("failed 3"); return false; });
if (!res3) {
// Do something if it is rejected again
....
}
// Otherwise, do your thing
Try this code, it should pinpoint where the error or rejection is occurring (i.e. it's definitely before Promise.all(promises2) is run
await axios.all(promises)
.then(res => axios.patch("/url", { foo: bar }), err => {
throw `all(promises) failed with ${err}`;
})
.then(() => {
const promises2 = arr.map(item => {
return axios.post("/url-2", item);
});
return Promise.all(promises2)
.then(() => console.log("resolved")) //this not calling ever
.catch(err => {
throw `all(promises2) failed with ${err}`;
});
}, err => {
throw `patch failed with ${err}`;
})
.catch(err => console.error(err));
Note I've removed async/await, because in the code you've posted it is totally unnecessary

Object mapping: Promise.all to catch iteration end and error

Let's say I want to perform a function on every value of an object.
How can I catch the end of the iteration and to know that no error has been made running the function on each value?
Object.keys(result).map(function(key, index) {
var value = result[key];
functiontorun(value, (result, error) => {
if (error) {
// catch the error
}
});
// AT THE END OF THE ITERATION
// if no error at all => then something
// if at least one error => then something else
});
Turn each request into a promise, and use Promise.all on the result:
const allPromises = Object.keys(result).map(function(key, index) {
var value = result[key];
return new Promise((resolve, reject) => {
functiontorun(value, (result, error) => {
if (error) {
// catch the error
reject(error);
} else resolve();
});
});
});
Promise.all(allPromises)
.then(() => console.log('all successful'))
.catch(err => console.log('at least one error ' + err));

Using throw in promises

I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
function promiseFunc(options) {
return new Promise(() => {
return options;
});
}
function myfunc(options) {
return new Promise(() => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then((result) => {
if (result.throwerr) throw new Error("thrown on purpose");
return result.value;
});
});
};
My test as follows:
const myfunc = require("./myfunc");
describe('myfunc', () => {
it('should fail without options', () => {
return myfunc()
.then((result) => { throw new Error(result) }, (err) => {
console.log("test #1 result:", err.message === "missing options");
});
});
it('should fail on options.throwerr', () => {
return myfunc({throwerr: true})
.then((result) => {}, (err) => {
console.log("test #2 result:", err.message === "thrown on purpose");
});
});
it('should return options.value', () => {
return myfunc({value: "some result", throwerr: false})
.then((result) => {
console.log("test #3 result:", result === "some result");
}, (err) => {});
});
});
The first test pass, but the second and third fails.
Log #2 does not even run, so I assumed the "throw on purpose" messes up something, therefore I created test #3, where I don't throw anything, but it still fails.
What am I missing?
Solution:
function promiseFunc(options) {
return new Promise(resolve => {
return resolve(options);
});
}
function myfunc(options) {
return new Promise((resolve, reject) => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then(result => {
if (result.throwerr) throw new Error("thrown on purpose");
return resolve(result.value);
}).catch(err => {
return reject(err);
});
});
};
You forgot to pass a function with resolve and reject parameters, so your promises just don't work.
function promiseFunc(options) {
return new Promise(resolve => { // resolve function
resolve(options)
})
}
module.exports = function myfunc(options) {
return new Promise((resolve, reject) => { // since you may either resolve your promise or reject it, you need two params
if (!options) {
return reject(new Error("missing options"))
}
return promiseFunc(options).then(result => {
if (result.throwerr) {
return reject(new Error("thrown on purpose"))
}
resolve(result.value)
})
})
}
... and the test (mocha)
const assert = require('assert'),
myfunc = require("./myfunc")
describe('myfunc', () => {
it('should fail without options', done => { // mind the callback, promises are always async
myfunc()
.catch(err => {
assert(err.message === "missing options")
done() // <- called here
})
})
it('should fail on options.throwerr', done => {
myfunc({throwerr: true})
.catch(err => {
assert(err.message === "thrown on purpose")
done()
})
})
it('should return options.value', done => {
return myfunc({value: "some result", throwerr: false})
.then(result => {
assert(result === "some result")
done()
})
})
})
I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
This will do it ...
var q = require('q'); // In recent versions of node q is available by default and this line is not required
function iReturnAPromise(num) {
var def = q.defer();
if (typeof num=== 'number') {
try {
var value = 100 / num;
def.resolve(value);
} catch(e) {
def.reject("oops a division error - maybe you divided by zero");
}
} else {
def.reject("o no its not a number");
}
return def.promise;
}
PS this function was coded freehand and has not been tested - but this will work. Obviously try catch should be used sparingly.
PS I prefer the q library implementation of promise instead of the default node promise library - they take a very different approach. q dispenses with all the wrapping!
using the promise library u wanted ...
function iReturnAPromise(num) {
return new Promise(function(resolve, reject) {
if (typeof num === 'number') {
try {
var value = 100 / num;
resolve(value);
} catch (e) {
reject("oops a division error - maybe you divided by zero");
}
} else {
reject("o no its not a number");
}
})
}
iReturnAPromise(7).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
// Unexpectedly this is not an error in node 5.6 because div by 0 is not an error operation anymore!
iReturnAPromise(0).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
iReturnAPromise("fred").then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
you can see why i prefer the q syntax :)

Categories

Resources