I have the following code:
fooService.update(this.bar).then( this.$emit('updated', this.updatedBar),).catch(err => {...
If an error is encountered, then the error is not caught. If I change the code to be:
fooService.update(this.bar).then(x => {this.$emit('updated', this.updatedBar);}).catch(err => {...
Then the error is caught and shows as expected. Can anyone explain to me what is going on and why it behaves in that way?
Edit
Underlying service code:
function updateBar(bar) {
return $http.put(`/api/bar/${bar.Id}`, bar);
}
So I still think the error is happening in the this.$emit the reason why, in
fooService.update(this.bar).then( this.$emit('updated', this.updatedBar),).catch(err => {
It has to evaluate the this.$emit first as you're setting the response from that function as the .then and not the call itself.
Proof of it doing that
function emit(){
console.log('emit')
}
var promise = new Promise(function(resolve,reject){
setTimeout(() => {
console.log('promise is done')
reject();
}, 1000)
})
promise.then(emit()).catch( function() {console.log('carry on');})
notice how it logs "emit" first
Now if that errors you can see it doesn't hit the catch
function emit(){
console.log('emit')
throw new Error("bad")
}
var promise = new Promise(function(resolve,reject){
setTimeout(() => {
console.log('promise is done')
reject();
}, 1000)
})
promise.then(emit()).catch( function() {console.log('carry on');})
So under the hood it's doing this (the simplest way I can think of)
emit()
try{
getService()
} catch{
...
}
Whereas if you actually pass the .then a function it changes the order of things
function emit(){
console.log('emit')
throw new Error("bad")
}
var promise = new Promise(function(resolve,reject){
setTimeout(() => {
console.log('promise is done')
reject();
}, 1000)
})
promise.then(() => {emit()}).catch( function() {console.log('carry on');})
and again under the hood it looks like this
try{
getService()
emit()
} catch{
...
}
Related
From the code below, I'm sending email using EmailJs library and the alert method get's executed after submitting but the change method doesn't. What I'm I missing?
Error message on the console is
Uncaught (in promise) TypeError: Cannot read property 'change' of undefined
at app.js:2755
My Script
<script>
import emailjs from "emailjs-com";
export default {
data() {
return {
flash: false,
};
},
methods: {
sendEmail: (e) => {
emailjs
.sendForm(
"service_k9mhh",
"template_epghgfh",
e.target,
"user_w9U76tg77yhcggh"
)
.then(
(result) => {
console.log("SUCCESS!", result.status, result.text);
alert("Message Sent Successfully")
this.change();
},
(error) => {
console.log("FAILED...", error);
}
);
// Reset form field
},
change(){
this.flash = true;
}
},
};
</script>
Without arrow functions as shown below, It still throws the same error.
methods: {
sendEmail: function (e) {
emailjs
.sendForm(
"service_",
"template_",
e.target,
"user_"
)
.then(
function (result) {
console.log("SUCCESS!", result.status, result.text);
this.change();
},
function (error) {
console.log("FAILED...", error);
}
);
},
change: function () {
this.flash = true;
}
The problem is that in arrow functions this does not refer to the Vue instance so this.change is not defined there.
Read this:
https://v2.vuejs.org/v2/guide/instance.html#Data-and-Methods
Okay so you and eldo were both half right. You need to use a regular function syntax when declaring a method, and an arrow function in any nested .then's.
Using an arrow function in your then and catch handler's ensures that 'this' remains a reference to the Vue instance.
Your method wants to look like this:
sendEmail(e) {
emailjs
.sendForm("service_", "template_", e.target, "user_")
.then((result) => {
console.log("SUCCESS!", result.status, result.text);
this.change();
})
.catch((error) => {
console.log("FAILED...", error);
});
},
I have an observable:
public updateThingName(name: string, thingId: number): Observable<any> {
console.log('attempting rename');
return this.http
.put(
`${this.thingApi}/projects/${thingId}`,
{ name },
this.options,
).pipe(
map(response => response.data.id)
);
}
called as part of a longer chain:
return this.projectService.getProject(id).pipe(
switchMap(prevProjectData => {
return this.projectService.updateProject(id, data).pipe(
map(newProjectData => ({prevProjectData, newProjectData}))
)
}),
switchMap(({prevProjectData, newProjectData}) => {
return this.thingService.updateThingName(newProjectData.title, newProjectData.thingId)
.pipe(retry(5),catchError(err => {
return this.projectService.revertProjectUpdate(err, prevProjectData);
}))
}),
tap(() => { ... save to logs only when successful ... })
);
I want to try to rename something, if it fails retry 5 times, if it still fails then catch the error, revert the earlier changes and throw the final error in the revert function. The reverting and sending the error response back to the front end works fine but no matter where I put the retry(5) I only ever see the initial console.log('attempting rename'); in the logs.
Am I miss using the retry? How do I get this to work?
This is backend code on NestJS so I don't handle the final subscribe aspects directly if that makes a difference.
Thanks!
That should be correct. The methodos called once but it tries to resubscribe multiple times. You should be able to see it if you log a message on every subscribe:
public updateThingName(name: string, thingId: number): Observable<any> {
return defer(() => {
console.log('attempting rename');
return this.http
.put(
`${this.thingApi}/projects/${thingId}`,
{ name },
this.options,
).pipe(
map(response => response.data.id)
);
)};
}
Curious issue I'm having dealing with some callback functions. I need to make a series of API calls that all return promises then I'm trying to take that data and map it to an array that exists on the global scope followed by a function to export the new data as a pdf - my issue is that the then() block is firing before the other function finishes and far before the first API call finshes. `
let fireWatson = async () => {
let watsonClassifed = []
let watsonCallIndex = 0;
let returnedArr = []
for (let i = 0; i < watsonData.length; i++) {
let params = {
classifierId: '***********',
collection: watsonData[i]
}
naturalLanguageClassifier.classifyCollection(params,
function (err, response) {
if (err)
console.log('error:', err);
else
console.log("data returned")
console.log(response.result.collection)
watsonClassifed.push(response.result.collection);
console.log(watsonClassifed)
})
}
}
fireWatson(watsonData).then(res =>
console.log("firing stupid callbback after data")
)
I realize this function isnt actually returning anything but is it possible to still make use of a promise without a return value or is this the main issue im hitting? Ideally - i want the then function to wait until the data is back - mapped to the global array and then outputted but this of course depends on proper synchronicity.
output:
[Done] exited with code=0 in 1.526 seconds
[Running] node "index.js"
firing stupid callbback
data returned
all my sweet sweet data
All functions in JavaScript have returns, it's just that they are implicit if you don't say return explicitly
It's always a bit tricky to mix promises with callbacks. Here is a way you can fireWatson without using any utilities.
let fireWatson = async watsonData => Promise.all(watsonData.map(collection => new Promise((resolve, reject) => {
let params = {
classifierId: '***********',
collection: collection,
}
return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
})))
Of course, you can simplify this tremendously using a utility I created
const { map } = require('rubico')
let fireWatson = map(collection => new Promise((resolve, reject) => {
let params = {
classifierId: '***********',
collection: watsonData[i]
}
return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
}))
turns out console.log was firing because every .then() block expects a function.
wrong:
fireWatson(watsonData).then(res =>
console.log("firing stupid callbback after data")
)
right:
fireWatson(watsonData).then(()res =>
console.log("firing stupid callbback after data")
)
My post is successful, but I can't do anything in the then statement except console.log(); it always jumps to the catch.
axios.post('/group/15/discussion/'+ this.discussion.id+ '/schedule',this.form, {handleErrors:true})
.then(function(response) {
//this.form.valid = true;
console.log("success");
console.log('set form valid');
this.$refs['schedule-group-discussion-'+this.id].hide();
console.log('close modal');
/*this.$emit('updateDiscussion',response.data.discussion);
this.$toast.success(response.data.message,'Success!',{icon: 'fas fa-check-circle'});*/
})
.catch((error) => {
console.log("catch");
this.form.valid = false;
});
here is my console log in order:
success
set form valid
catch
What is wrong?
The problem is your scope of this. You're actually getting an error, cannot read property valid of undefined, but you didn't console.log(error). You need to use the fat arrow function in your .then() as well:
.then(function(response) {
to
.then((response) => {
Now this is scoped correctly.
In my project, I use RxJS to handle HTTP request. I came into a confusing point about the error handling part as following:
.switchMap((evt: any) => {
return http.getComments(evt.params)
.map(data => ({ loading: false, data }))
.catch(() => {
console.log('debugging here');
return Observable.empty();
});
})
in the above code, inside the switchMap operator, I use the http.getComments function to send request, which is defined by myself as following:
getComments(params) {
return Observable.fromPromise(
this.io.get(path, { params })
);
}
in this function, I use fromPromise operator convert the returned Promise to observable.
The problem is when HTTP request failed, the catch operator inside switchMap can not work, the debugging console can't output. So what's wrong with my code.
Do you really need to catch the error inside the switchMap anyway? You can handle your error in your source if you want.
.switchMap((evt: any) =>
http.getComments(evt.params).map(data => ({ loading: false, data }))
})
.subscribe(console.log, console.error);
Any way, your source code does not look to have any error, maybe your promise is not been rejected when the http fails and is just resolving with an error as a response (this is a guess because I've seen that before)
Your code should work. Here a simplified simulation, where http calls are substituted by a function which raises an error.
import {Observable} from 'rxjs';
function getComments(params) {
return Observable.throw(params);
}
const params = 'abc';
Observable.of(null)
.switchMap(_ => {
return getComments(params)
.map(data => ({ loading: false, data }))
.catch(err => {
console.log('debugging here', err);
return Observable.empty();
});
})
.subscribe(
console.log,
error => console.error('This method is not called since the error is already caught', error),
() => console.log('DONE')
)