**
UPDATE
I already know my mistake but now I need help on how to add a splice, in each function I have a push that adds the data in x position, my question is, how can I change that push for a splice and tell it what position I want it to take that data by that the promise.all when it is executed is random and I could not know the position that is why it gave me an error at the beginning, in this part I use the push, I must change them to splice:
this.opcionServicio = response;
this.opcionesServicio.push(this.opcionServicio);
this.servicio.push(this.opcionesServicio[0].ticket_field.title)
customFieldOption.id = this.opcionServicio.ticket_field.id;
customFieldOption.name = this.opcionServicio.ticket_field.title;
this.customFieldOptions.push(customFieldOption);
**
I have a question, does anyone know why my code doesn't work? I have 4 functions, each function is a promise and in the ngOnInit it loads these functions, I put them with a Promise.all, in the console it prints the array but when I enter the screen the "loading" does not appear and it does not appear the information I want...
processing is a "loading" type
I only put 2 functions but the other 2 have almost the same
ngOnInit(): void {
Promise.all([this.getData1, this.getData2]).then(values => {
console.log(values)
this.processing = true;
}).catch(reason => {
console.log('error get data',reason)
});
}
public getData1() {
return new Promise((resolve, reject) => {
this.createService.getServiceData1().subscribe(
(response: any) => {
let customFieldOption: CustomFieldOption = new CustomFieldOption();
this.opcionServicio = response;
this.opcionesServicio.push(this.opcionServicio);
this.servicio.push(this.opcionesServicio[0].ticket_field.title)
customFieldOption.id = this.opcionServicio.ticket_field.id;
customFieldOption.name = this.opcionServicio.ticket_field.title;
this.customFieldOptions.push(customFieldOption);
resolve(true);
},
(error) => {
console.log(error);
reject(true);
}
);
});
}
public getData2() {
return new Promise((resolve, reject) => {
this.createService.getServiceData2().subscribe(
(response: any) => {
let customFieldOption: CustomFieldOption = new CustomFieldOption();
this.opcionServicio = response;
this.opcionesServicio.push(this.opcionServicio);
this.servicio.push(this.opcionesServicio[0].ticket_field.title)
customFieldOption.id = this.opcionServicio.ticket_field.id;
customFieldOption.name = this.opcionServicio.ticket_field.title;
this.customFieldOptions.push(customFieldOption);
resolve(true);
},
(error) => {
console.log(error);
reject(true);
}
);
});
}
Related
In the code below , Values are RETURNED correctly from a queued Promise.then() chain .
CODE:
let cond_1 = true;
let data = 'Data Received....';
let err = 'Error';
var p1 = new Promise(function(resolve,reject){
if(cond_1){
resolve(data);
}else{
reject(err); }})
p1.then((data)=>{console.log(data);return 'Wait....';})
.then((val1)=>{console.log(val1); return 'Finished';})
.then((val2)=>{console.log(val2)})
.catch((err)=>{console.log(err)});
Output :
Data Received....
Wait....
Finished
However, the same RETURNED values from a chained SetTimeout function are returned 'UNDEFINED'.
CODE:
p1.then((data)=>{console.log(data); return 'Wait.....'; })
.then((val1)=>{setTimeout(function(val1){console.log(val1); return 'Finished';},1000)})
.then((val2)=>{setTimeout(function(val2){console.log(val2);},1000)})
.catch((err)=>{console.log(err)});
Output:
Data Received....
undefined
undefined
How to resolve this?
Try taking advantage of Lexicographic nature of Javascript.
Instead of making a function v1,v2 which your functions takes within setTimeout, just use an arrow function. In this way you are using the v1,v2 returned from promise.
Do this
let cond_1 = true;
let data = 'Data Received....';
let err = 'Error';
var p1 = new Promise(function(resolve, reject) {
if (cond_1) {
resolve(data);
} else {
reject(err);
}
})
p1.then((data) => {
console.log(data);
return 'Wait.....';
})
.then((val1) => {
setTimeout(() => {
console.log(val1);
}, 1000);
return 'Finished';
})
.then((val2) => {
return setTimeout(() => {
console.log(val2)
}, 1000)
})
.catch((err) => {
console.log(err)
});
What you did was you created a new variable v1,v2 for your function. You can only use that when you pass value v1,v2 in that function. That function won't use v1,v2 returned from promise as you expect.
I am developing a SPFx WebPart using TypeScript.
I have a function to get a team by name (get() returns also a promise):
public getTeamChannelByName(teamId: string, channelName: string) {
return new Promise<MicrosoftGraph.Channel>(async (resolve, reject) => {
this.context.msGraphClientFactory
.getClient()
.then((client: MSGraphClient) =>{
client
.api(`/teams/${teamId}/channels`)
.filter(`displayName eq '${channelName}'`)
.version("beta")
.get((error, response: any) => {
if ( response.value.length == 1) {
const channels: MicrosoftGraph.Channel[] = response.value;
resolve(channels[0]);
} else if (response.value.length < 1) {
reject(new Error("No team found with the configured name"));
} else {
reject(new Error("Error XY"));
}
});
})
.catch(error => {
console.log(error);
reject(error);
});
});
}
I call this function like this:
public getConversations(teamName: string, channelName: string, messageLimitTopics: number = 0, messageLimitResponses: number = 0) {
return new Promise<any>(async (resolve, reject) => {
try {
this.getTeamGroupByName(teamName)
.then((teamGroup: MicrosoftGraph.Group) => {
const teamId: string = teamGroup.id;
this.getTeamChannelByName(teamId, channelName)
.then((teamChannel: MicrosoftGraph.Channel) => {
const channelId: string = teamChannel.id;
this.getChannelTopicMessages(teamId, channelId, messageLimitTopics)
.then((messages: MicrosoftGraph.Message[]) => {
const numberOfMessages = messages.length;
... // omitted
});
});
});
} catch(error) {
reject(error);
}
});
}
And this getConversations() function itself is called from my webpart code:
public getConversations() {
if (this.props.teamName && this.props.teamName.length > 0 &&
this.props.channelName && this.props.channelName.length > 0) {
GraphService.getConversations(this.props.teamName, this.props.channelName, this.props.messageLimitTopics, this.props.messageLimitResponses)
.then((conversations) => {
.. // omitted
})
.catch((err: Error) => {
console.log(err);
this.setState({errorMessage: err.message});
});
} else {
// Mandatory settings are missing
this.setState({errorMessage: strings.MandatorySettingsMissing});
}
}
So, as you can see, above, I want to write out the error (message) I receive from the reject inside the getConversations() functions. The problem is, that I don't receive this rejection with the error, but in the console I see the following:
Uncaught Error: No team found with the configured name
I added the .catch() blocks you see above inside getTeamChannelByName() but this doesn't get hit during debugging.
Haven't worked much with promises and I am still confused a bit about them, so I guess that I probably have constructed the promise chain wrongly, maybe placed the catch block(s) in the wrong position(s)?
I had a look at common mistakes done with Promises and I certainly had what is called a "Promise Hell".
So, I am not 100% sure yet, but I guess, the result of this was that there was no catch block for my .then("Promise") so the rejection went to nowhere.
I have now changed the calling method to this, and I also removed the try/catch blocks, as it is unnecessary:
public getConversations(teamName: string, channelName: string, messageLimitTopics: number = 0, messageLimitResponses: number = 0) {
return new Promise<any>(async (resolve, reject) => {
let teamId: string = null;
let channelId: string = null;
this.getTeamGroupIdByName(teamName)
.then(tId => {
teamId = tId;
return this.getTeamChannelIdByName(teamId,channelName);
})
.then(cId => {
channelId = cId;
return this.getChannelTopicMessages(teamId, channelId, messageLimitTopics);
})
.catch(error => {
reject(error);
});
});
}
The requirement is finishing the current function before moving to the next call:
var current_data = something;
Run(current_data).then((data1) => {
Run(data1).then(data2 => {
Run(data2).then(data3 => {
// and so on
})
})
});
The example above is only possible if I know exactly how much data I want to get.
In order to make the nested promises part of promise chain, you need to return the nested promises.
Run(current_data).then((data1) => {
return Run(data1).then(data2 => {
return Run(data2).then .....
});
});
I'm gonna assume your data is paginated and you don't know how many pages there are, therefore you can use a while loop with await inside of an async function like so:
(async function() {
var currentData = someInitialData;
// loop will break after you've processed all the data
while (currentData.hasMoreData()) {
// get next bunch of data & set it as current
currentData = await Run(currentData);
// do some processing here or whatever
}
})();
You can use the async-await to make code more readable.
async function getData(current_data){
let data1 = await Run(current_data)
let data2 = await Run(data1);
let result = await Run(data2);
return result;
}
Calling the getData function
getData(data)
.then(response => console.log(response))
.catch(error => console.log(error));
Try to avoid nested promises. If you need to call a series of promises, which depend on the previous call's response, then you should instead chain then like the following following -
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 1000);
});
promise1.then((response) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(response + ' b');
}, 1000);
});
}).then((responseB) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(responseB + ' c');
}, 1000);
});
}).then((responseC) => {
console.log(responseC); // 'foo b c'
})
if your code can support async-await then what Mohammed Ashfaq suggested is an alternative.
If you are executing the same function over and over again but on different data, I would make a recursive function that returns return a Promise.
I just look at my example below using an an array of numbers, you can edit it to your current case.
var current_data = [1,2,4,5,6]
function Run(data){
if(data.length === 0)
return Promise.resolve(data);
return new Promise((resolve, reject)=>{
//your async operation
//wait one second before resolving
setTimeout(()=>{
data.pop()
console.log(data)
resolve(data)
},1000)
})
.then((results)=>{
return Run(results)
})
}
Run(current_data)
I recently met a problem with promise Chain in javascript, specifically in Vue.js.
This is my code, I have a addItem function that insert an item in database. I want to have this function run it insert things in database then use getItems function to renew all the data. However, what I find out is that this function will run the things in the .then first then insert the item in the database at last. This caused my code to break. If any of you can help me that will be great!
addItem: function() {
this.$store.dispatch('addJournal',{
journal: this.text,
page: this.maxPage + 1, // increase the page number
}).then(response => {
this.text = ""; // set the input to empty
this.getItems(); // get all the data from database
this.setMaxPage(); // reset the max size
this.currentPage = this.maxPage; // go to the max page
this.option = "current";// set back to current
}).catch(err => {
});
},
this is other corresponding code
getItems: function() {
this.pages = [];
var tempArray = [];
tempArray = this.$store.getters.feed;
for (var index = 0; index < tempArray.length; ++index) {
let page = {text:tempArray[index].journal,
pageNumber:tempArray[index].page};
this.pages.push(page);
}
},
this is the addJournal function in store.js
addJournal(context,journal) {
console.log("this is for users", context.state.user.id)
axios.post("/api/users/" + context.state.user.id + "/journals",journal).then(response => {
return context.dispatch('getFeed');
}).catch(err => {
console.log("addJournal failed:",err);
});
context.dispatch('getFeed');
}
You need to convert addJournal into something that returns a promise, so that it can be consumed with then:
addJournal(context, journal) {
console.log("this is for users", context.state.user.id)
context.dispatch('getFeed');
return axios.post("/api/users/" + context.state.user.id + "/journals", journal).then(response => {
return context.dispatch('getFeed');
}).catch(err => {
console.log("addJournal failed:", err);
});
}
Not sure what context.dispatch('getFeed'); does, but since posting is asynchronous, there shouldn't be anything wrong with moving it above the axios.post line. axios.post returns a promise already, so you just need to return it.
.then() works on promise
for this.$store.dispatch('addJournal').then(...) to work as expected, addJournal should be a promise.
Here's how
addJournal(context, journal) {
return new Promise((resolve, reject) => {
axios
.post("/api/users/" + context.state.user.id + "/journals", journal)
.then(response => {
context.dispatch("getFeed");
resolve();
})
.catch(err => {
console.log("addJournal failed:", err);
reject(err);
});
});
}
I am new to promises and trying to figure out for quite a long time now how to get proper results after the usage of a async network call with which I receive data.
I receive my balance from a exchange and loop through several parameters. When this is finished the holdings should be returned.
However, I still have to fight the async behaviour. When I run the code without the commented code, the result is []. If I set a artificial setTimeout, then the returned array holdings is visible properly.
Can someone tell me please where my mistake lays? I tried to read through docs of mdn and similar problems here on stackoverflow but I am nonetheless stuck.
Thank you guys very much,
Tobias
const bittrex = require('node.bittrex.api');
const {key, secret} = require('./key')
let getBalance = new Promise((resolve, reject) => {
let holdings = [];
bittrex.getbalances( function( data, err ) {
if (err) {
reject(err);
}
data.result.forEach(coin => {
if (coin.Balance !== 0) {
let market = `BTC-${coin.Currency}`;
if(coin.Currency === 'BTC') market = `USDT-BTC`;
bittrex.getticker( { market : market}, function( ticker, err ) {
if (err) {
reject(err);
}
holdings.push({
Coin: coin.Currency,
Balance: coin.Balance,
Last: ticker.result.Last
});
})
}
});
});
resolve(holdings);
})
getBalance
// .then((holdings) =>{
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(holdings);
// }, 10000)
// })
// })
.then((holdings) => {
console.log(holdings);
})
You're resolving your promise instantaneously but the data is not here yet, as it is happened asynchronously during the callback. Your promise should be resolved after every callback.
What you should do is create a promise for each of the request and then resolve your function with a Promise.all
const bittrex = require('node.bittrex.api');
const {key, secret} = require('./key')
let getBalance = new Promise((resolve, reject) => {
let holdings = [];
bittrex.getbalances( function( data, err ) {
if (err) {
reject(err);
}
const promises = data.result.map(coin => new Promise((resolve, reject) => {
if (coin.Balance !== 0) {
let market = `BTC-${coin.Currency}`;
if(coin.Currency === 'BTC') market = `USDT-BTC`;
bittrex.getticker( { market : market}, function( ticker, err ) {
if (err) {
reject(err);
}
resolve({
Coin: coin.Currency,
Balance: coin.Balance,
Last: ticker.result.Last
});
})
}
});
resolve(Promise.all(promises));
});
});
Your getBalance promise will be resolved when all of your promise are resolved. Be cautious though, if one of your promise is rejected, then the whole promise will be rejected.
If it's properly resolved, then the value will be an array of each value of the promises.
Since I'm assuming bittrex.getticker is async, you should instead just wrap each call into a promise and not try to combine them into one manually.
Here's a loose concept.
function getTicker(...) {
return new Promise(function(resolve, reject) {
bittrex.getticker(..., function(ticker, error) {
if (error) { reject(error); }
else { resolve(ticker); }
});
});
}
var lotsOfPromises = data.result.map(function(coin) {
return getTicker(...).then(function(ticker) {
return { yourOutputdata }
});
});
Promise.all(lotsOfPromises);