如何避免缩进嵌套承诺?

时间:2020-12-30 23:00:36

标签: javascript es6-promise

我听说承诺在代码中应该是线性的,而不是回调(“回调地狱”)。

尽管我仍然有一个类似于回调地狱的场景,并希望 promise 能够做出他们的承诺,并具有与此问题代码等效的线性语法。

鉴于承诺 p()q()w(),请考虑以下代码:

p().then(() => {
    q().then(() => {
       w().then(() => {
           // do something
       })
    })
})

我们能否编写一个不为每个嵌套 promise 缩进的等效代码?

3 个答案:

答案 0 :(得分:3)

正如另一位用户所提到的,您可以使用 async/await,但另一种选择只是稍微重组您所拥有的内容。以下是一些可行的示例,具体取决于您何时何地需要某些数据:

p()
  .then(q)
  .then(w)

// OR

p()
  .then(() => q())
  .then(() => w())

显然,如果 w() 需要来自 p()q() 的数据,这会变得有点复杂,但这就是它的要点。

答案 1 :(得分:2)

您不应嵌套 .then() 处理程序,而应让每个 .then() 创建并返回一个新的 Promise。这就是它的设计方式,否则你仍然在回调地狱中,现在是带有承诺的版本。没有太大区别。

代码应该是这样的:

p()
  .then(() => {
    return q();
  })
  .then(() => {
    return w();
  })
  .then(() => {
    // do something
  });

如果 .then() 处理程序所做的只是调用下一个函数,您可以用更简单的形式编写它(阅读 arrow functions):

p()
  .then(() => q())
  .then(() => w())
  .then(() => {
    // do something
  });

更重要的是,如果在没有参数的情况下调用 qw,则代码可以像这样简单:

p()
  .then(q)
  .then(w)
  .then(() => {
    // do something
  });

或者您可以加倍努力,而不是使用 .then().catch(),而是使用 await。代码变得更加清晰易读:

try {
  await p();
  await q();
  await w();
  // do something
} catch (err) {
  // write here the code you would write in the handler you pass to `.catch()
  // in the approach that uses Promises
}

备注

如果上面使用 await 的代码在函数中使用,则该函数必须是 async function(只需将 async 放在其定义前面)。

使用 await may or may not be used outside of a function 的代码(即在模块的顶层)取决于您用来运行它的运行时(浏览器、Node.js 等)。

答案 2 :(得分:1)

您可以尝试使用 async/await,这样代码会更简洁。应该是这样的:

(async () => {
    try {
        await p();
        await q();
        await w();
    } catch (e) {
        // handle error
    }
})()

如果每个 promise 之间没有依赖关系,您可以使用 await Promise.all 来执行“全有或全无”。在任何其他情况下,您可以存储返回值并将其传递给下一个函数,以便在需要时使用。