【问题标题】:How can I eliminate these nested Promises?如何消除这些嵌套的 Promise?
【发布时间】:2017-08-02 16:57:55
【问题描述】:

我读到您应该避免 JavaScript 中的嵌套承诺,因为它们往往是一种反模式,但我无法弄清楚如何在我的特定用例中避免它们。希望比我更有经验的人能看到我哪里出错了?任何建议将不胜感激!

基本上,我异步检索一些数据,处理它并捕获可能的错误,然后异步保存一些数据。这是一个非常简化的示例:

class Foo {
  changeName(path, newName) {
      this.getPage(path) // AJAX call, returns a promise with type Page,
                         //  may throw an Error if the page does not exist.
        .then(page=> {
          // Some modifications are made to page, omitted here
          return page
        })
        .catch(e=>{
          if(e instanceof PageDoesNotExistError) {
            return new Page();
          }
        })
        .then(page=> {
          page.name = newName;
          this.savePage(path, page); // ******
          // I want my outer changeName method to return this ^ promise,
          // or at least a promise that will resolve when this promise
          // resolves, with the same value.
        })
  }
}

我怎样才能让changeName 返回一个将解析为this.savePage 值的承诺(标有//****** 的行),以便我可以在其他地方做这样的事情:

myFooInstance.changeName('/path', 'New Name').then(page=> {
  // Do something with the returned saved page
});

【问题讨论】:

  • 呃,只是return 吗?请注意,还没有任何嵌套。

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


【解决方案1】:

如何让 changeName 返回一个可以用 this.savePage 的值解决的承诺

返回从 then 处理程序返回的承诺 savePage。这会将then 创建的promise 解析为savePage 的promise,这意味着then 创建的promise 将根据savePage 的promise 执行或拒绝。 (如果您有兴趣,请在my blog post here 中详细了解该术语。)

.then(page=> {
    page.name = newName;
    return this.savePage(path, page);
})

另外,你说过你希望调用者能够在changePage 的返回值上使用承诺,但你没有从changePage 返回任何东西。您需要在整个结构之前添加return,以便您返回最终的承诺。

changeName(path, newName) {
    return this.getPage(path) // AJAX call, returns a promise with type Page,
    // ...

(完整版本见下文。)


旁注:这里有一个错误等待发生:

.catch(e=>{
    if(e instanceof PageDoesNotExistError) {
        return new Page();
    }
})

如果e 不是PageDoesNotExistError 的实例,则您将拒绝转换为具有值undefined 的解决方案,因为您的catch 处理程序在这种情况下不会返回显式值。如果您想传播错误,则需要使用throw ereturn Promise.reject(e)

.catch(e=>{
    if(e instanceof PageDoesNotExistError) {
        return new Page();
    }
    return Promise.reject(e);
})

将所有这三件事结合在一起:

class Foo {
    changeName(path, newName) {
        return this.getPage(path)
            .then(page=> {
                // Some modifications are made to page, omitted here
                return page;
            })
            .catch(e=>{
                if(e instanceof PageDoesNotExistError) {
                    return new Page();
                }
                return Promise.reject(e);
            })
            .then(page=> {
                page.name = newName;
                return this.savePage(path, page);
            });
    }
}

【讨论】:

  • @jfriend00:我对我的承诺骗子很弱。你有一个方便的覆盖这个我可以添加到我的列表中吗?
  • 感谢您报道单分支if 声明。很多开发者都错过了这个
  • 问题已修复 if javascript 消除了单分支条件 else 坚持致命的陷阱 ^_^
  • 非常感谢!这比我预期的要简单得多!
【解决方案2】:

您只需返回承诺,然后从任何嵌套的承诺中返回:

class Foo {
  changeName(path, newName) {
      return this.getPage(path)
        .catch(e => {
          if(e instanceof PageDoesNotExistError) {
            return new Page();
          }
        })
        .then(page=> {
          page.name = newName;

          return this.savePage(path, page); // assuming that this is a promise
        })
  }
}

【讨论】:

  • 即使this.savePage 不是承诺,也没关系。 Promise.then 自动将非 Promise 返回值提升为 Promise。
猜你喜欢
  • 2018-12-24
  • 2014-03-26
  • 2017-09-06
  • 2017-04-15
  • 1970-01-01
  • 2018-09-16
相关资源
最近更新 更多