【问题标题】:How to create a Promise for nested async calls如何为嵌套的异步调用创建 Promise
【发布时间】:2017-12-24 02:29:57
【问题描述】:

我有两个函数正在开始异步加载资源。我怎样才能让他们返回我可以等到加载完成的承诺?

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

我想获得一个(或两个)Promise,这样我就可以等到两者都完成,即加载文件并链接模板。我只是不知道如何获得它们以便可以将它们退回。简单地将return 放在每个函数的第一行前面不会为嵌套任务返回正确的函数。我是否必须在这里更改我的设计才能等待最里面的任务?

【问题讨论】:

  • 啊!你为什么用$.when而不是Promise.all
  • 我刚学ES6,谢谢你的建议。
  • this code 能解决您的问题吗?我不太确定你想要诚实的承诺
  • @JaromandaX 是的!非常感谢!

标签: javascript asynchronous ecmascript-6 promise es6-promise


【解决方案1】:

简单地将return 放在每个函数的第一行前面不会为嵌套任务返回正确的函数

其实会的。你确定你把它放在所有四个函数的第一行吗?

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

关于LoadMaps,您可能一直在考虑同时运行两个getFile 调用。你可以再次使用Promise.all 来做到这一点:

LoadMaps() {
  return Promise.all([
//^^^^^^
    gFileService.getFile('syn-maps.json').then(mapItem =>
      this.synMaps = mapItem
    ),
    gFileService.getFile('sense-maps.json').then(mapItem =>
      this.senseMaps = mapItem
    )
  ]);
}

甚至

LoadMaps() {
  return Promise.all([
    gFileService.getFile('syn-maps.json'),
    gFileService.getFile('sense-maps.json')
  ]).then(results => {
    [this.synMaps, this.senseMaps] = results
  });
}

【讨论】:

  • OP 可以通过取消嵌套第二次来避免第二次返回。
  • @danh 他可以避免嵌套,但不能避免返回
  • 啊好吧,我只想到了外面的returns。如果内部函数也返回 promise,那么外部函数会自动等待它们吗?
  • 第一次返回不是返回整个链吗? ES6函数的最后一行是隐式返回,不是吗?
  • @FelixDombek 是的,then 方法 returns a promise for the result of the callback
【解决方案2】:

如果您只需要知道最后一次调用何时完成,您可以简单地使用这个框架:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-29
    • 2016-06-01
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    相关资源
    最近更新 更多