I have two functions which are starting asynchronous loading of resources. How can I make them return promises to that I can wait until the loading is finished?
// #1
LoadMaps() {
gFileService.getFile('syn-maps.json').then(
mapItem => this.synMaps = mapItem
).then(
gFileService.getFile('sense-maps.json').then(
mapItem => this.senseMaps = mapItem
)
);
}
// #2
LoadListAndMetadata() {
gListService.getList().then(lexList => {
let promises = [];
lexList.forEach(lexItem => {
lexItem.selected = false;
this.lexList[lexItem.lexId] = lexItem;
if (lexItem.hasMeta) {
promises.push(gFileService.getFile(lexItem.metaFile).then(
metaItem => this.metadata[lexItem.lexId] = metaItem
));
}
});
$.when(...promises).then(
() => $.templates('#lexSelectionTemplate').link('#lexSelection', this)
);
});
}
I would like to get a Promise (or two) so that I can wait until both are finished, i.e. the files are loaded and the template is linked. I just don't see how I could obtain them so that they can be returned. Simply putting return
in front of the first line of each function will not return the correct one for the nested tasks. Do I have to change my design here to be able to wait on the innermost tasks?
Simply putting return
in front of the first line of each function will not return the correct one for the nested tasks
Actually it will. Are you sure your put it on the first line of all four functions?
LoadMaps() {
return gFileService.getFile('syn-maps.json').then(
//^^^^^^
mapItem => this.synMaps = mapItem
).then(() => { // <== admittedly, you forgot this entire function
return gFileService.getFile('sense-maps.json').then(
// ^^^^^^
mapItem => this.senseMaps = mapItem
)
});
}
LoadListAndMetadata() {
return gListService.getList().then(lexList => {
//^^^^^^
let promises = [];
lexList.forEach(lexItem => {
lexItem.selected = false;
this.lexList[lexItem.lexId] = lexItem;
if (lexItem.hasMeta) {
promises.push(gFileService.getFile(lexItem.metaFile).then(
metaItem => this.metadata[lexItem.lexId] = metaItem
));
}
});
return Promise.all(promises).then(
// ^^^^^^
() => $.templates('#lexSelectionTemplate').link('#lexSelection', this)
);
});
}
Regarding LoadMaps
, you might have been thinking in terms of running the two getFile
calls concurrently. You can do that using Promise.all
again:
LoadMaps() {
return Promise.all([
//^^^^^^
gFileService.getFile('syn-maps.json').then(mapItem =>
this.synMaps = mapItem
),
gFileService.getFile('sense-maps.json').then(mapItem =>
this.senseMaps = mapItem
)
]);
}
or even
LoadMaps() {
return Promise.all([
gFileService.getFile('syn-maps.json'),
gFileService.getFile('sense-maps.json')
]).then(results => {
[this.synMaps, this.senseMaps] = results
});
}
If all you need is to know when the last call has completed you can simply use this skeleton:
function firstCall() {
return new Promise((y,n) => setTimeout( () => y('firstCall'), 500 ));
}
function secondCall() {
return new Promise((y,n) => setTimeout( () => y('secondCall'), 800 ));
}
function promiseTest() {
Promise.all([
firstCall(),
secondCall()
]).then( function(data) {
console.log( data );
})
.catch( function(err) {
console.log( 'Error executing promisses.', err );
});
}
promiseTest();