Javascript 如何在.then.catch链中有条件地运行.then()函数?

Javascript 如何在.then.catch链中有条件地运行.then()函数?,javascript,asynchronous,ecmascript-6,promise,es6-promise,Javascript,Asynchronous,Ecmascript 6,Promise,Es6 Promise,我的代码类似于: router.post("/", (req, res, next) => { foo() .then((result) => { res.send(result) }) .catch((error) => { cosnole.log(error) }) //I only want the bar() function and everything below it to run if the first promise is rejected

我的代码类似于:

router.post("/", (req, res, next) => {
foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    cosnole.log(error)
})
//I only want the bar() function and everything below it to run if the first promise is rejected and the first .catch function ran
bar()
.then((data) => {
    res.send(data)
})
.catch((error) => {
    console.log(error)
})
})

我只希望在第一个承诺被拒绝并且.catch函数启动时,才在它之后运行bar()函数和.then.catch函数

我试过这个:

router.post("/", (req, res, next) => {
rejected = false
foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    rejected = true
    console.log(error)
})
if(rejected == true)
    bar()
    .then((data) => {
        res.send(data)
    })
    .catch((error) => {
        console.log(error)
    })
})

但是,当捕捉到第一个foo()函数的错误并拒绝承诺时,bar()函数永远不会执行。

将调用移到捕捉内部

router.post("/", (req, res, next) => {
    foo()
    .then((result) => {
        res.send(result)
    })
    .catch((error) => {
        cosnole.log(error);
        return bar()
        .then((data) => {
            res.send(data)
        })
        .catch((error) => {
            console.log(error)
        });
    });
});

试着把你的承诺串起来

router.post("/", (req, res, next) => {
    foo()
    .then((result) => {
        res.send(result)
    })
    .catch((error) => {
        console.log(error);
        return bar;
    })
    .then((data) => {
        res.send(data);
    })
    .catch((error) => {
        console.log(error)
    });
});
-----------------编辑-----------------

下面是一份可完全测试的ExpressJS示例副本,其中包含您的问题:

const express = require("express");
const app = express();
const port = process.env.PORT || 4000;

app.get("/", function(req, res) {
    foo = new Promise(function(resolve, reject) {
        // resolve("resolved"); // Uncomment for resolve
        reject("rejected");
    });

    bar = new Promise(function(resolve, reject) {
        resolve("myData");
    });

    foo.then((result) => {
        res.send(result);
    }).catch((error) => {
        console.log(error);
        return bar;
    }).then((data) => {
        res.send(data);
    });
});

app.listen(port, function () {
    console.log("Listening on port: " + port);
});

考虑到代码的异步性质,
if(rejected==true)
将始终是
false
,因为该代码在第一个
之前执行,然后是
catch

你可以:

移动.catch()中的所有bar()[…]代码 在.catch()之后移动.then()中的所有条件执行
I/O调用是异步进行的,因此,
if
代码在res.send()返回任何响应之前运行。有几种方法可以处理这种情况,下面是另一种使用
asyn/await
来编写类似同步的代码的方法:

router.post("/", async (req, res, next) => {
rejected = false
try {
  await foo()
    .then((result) => {
      res.send(result)
    })
} catch {
  rejected = true
  console.log(error)
}
if(rejected == true)
  bar()
  .then((data) => {
    res.send(data)
  })
  .catch((error) => {
    console.log(error)
  })
})

正如其他人提到的,您只需要将代码移动到
catch
处理程序中

但是,您可能希望简化并更正代码,以

router.post("/", (req, res, next) => {
    foo().catch(bar).then(result => {
        res.send(result);
    , error => {
        console.error(error);
        res.sendStatus(500); // or next(error) or whatever
    });
})
如果您想记录
foo
中的错误,即使它们是由
bar
处理的,您可能需要

foo().catch(error => {
    console.log(error, "(handled by bar)");
    return bar();
}).…


承诺不应该解决嵌套回调问题吗?@doodlemeister结构化编程要求对控制流进行嵌套。您仍然可以通过简单的返回链接到它上,@Bergi:嵌套函数不是必需的,即使没有承诺。嵌套/闭包只是管理数据集合的一种惰性方式。我不相信在没有进一步嵌套的情况下,解决这个问题只需要几秒钟。不需要“魔法”。@doodlemeister对于闭包来说,我们总是需要至少一级嵌套,但是是的,我们可以提取命名函数并显式管理作用域环境。内联编写它们更简单,而且通常更可读。@Bergi:闭包并不是真正需要的,但一个级别对于封装只与当前操作相关的函数确实有用。如果使用匿名回调实际上更干净,那么我们将在所有方面都使用它们。相反,我们(至少在我看到的大多数代码中)创建命名函数来组织代码。我不明白为什么异步代码会有什么不同。。。但那只是我。;-)如果您的代码在then()之前执行过,则会得到解析。您确定吗?我在这段代码中看不到任何东西告诉我第二个
。那么只有在第一个
catch
触发时才会发生
。它怎么知道它得到了什么数据呢?嗨,Doodle Meister,我提供了一个服务器示例来回答你的问题。我想知道答案被否决的原因,因为Doodle Meister是正确的。您的代码调用
res.send
两次,这是一个错误。未尝试服务器部件,但您得到
log(“拒绝”);发送(“myData”)
(当foo拒绝时)或
发送(“已解决”);发送(未定义)
(当foo完成时)。颤抖。即使在这里,代码也应该在
catch
块中移动。当您使用
async
/
wait
时,您应该在任何地方都使用它-并且没有单个
然后
catch
回调left我没有得到它。我不想得到相同的模式,也不想把事情搞混,但为什么要先在内部使用
if
catch
?我建议根本不要使用
if
。当您可以直接表达它时,不需要使用控制流标志。我从来没有想过要反转catch/then(更不用说删除重复代码)。这更清晰/可读性更强。(+1)是的,代码在语义上不再严格等同于您的,但是重复的
。然后(res.send)
只是请求在链的末尾共享我会这样格式化我的代码,但是bar()函数发送的有效负载与res.send()@SirSudo中的foo()函数的名称不同。你说什么“名称不同”?您应该始终能够将其转换为通用格式。
router.post("/", (req, res, next) => {
    foo().catch(bar).then(result => {
        res.send(result);
    , error => {
        console.error(error);
        res.sendStatus(500); // or next(error) or whatever
    });
})
foo().catch(error => {
    console.log(error, "(handled by bar)");
    return bar();
}).…