0

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?

4
  • 1
    ugh! Why are you using $.when instead of Promise.all Commented Jul 19, 2017 at 2:42
  • I'm just learning ES6, thanks for your suggestion. Commented Jul 19, 2017 at 2:43
  • 1
    does this code solve your problem? I'm not too sure which promise(s) you want to be honest Commented Jul 19, 2017 at 2:44
  • @JaromandaX Yes it did! Thanks so much! Commented Jul 19, 2017 at 2:53

2 Answers 2

1

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
  });
}
Sign up to request clarification or add additional context in comments.

6 Comments

OP could avoid the second return by un-nesting the the second then.
@danh He could avoid the nesting, but not the return
Ah ok, I only thought about the outer returns. If the inner functions return promises too, then the outer ones will wait for them automatically?
Wouldn't that first return return the whole chain? The last line of the ES6 function is implicit return, isn't it?
@FelixDombek Yes, the then method returns a promise for the result of the callback
|
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.