【问题标题】:Promise chaining: Use result from previous promise in next then callback [duplicate]承诺链:在下一个然后回调中使用前一个承诺的结果[重复]
【发布时间】:2015-01-10 06:01:17
【问题描述】:

我正在使用直接的 ES6 Promises(使用 es6-promise polyfill 库),并且在访问链式承诺中的先前承诺的结果时遇到了问题。

这个问题在Angular/Q的上下文中是一样的,但是我对答案不满意,想看看有没有更好的方法:

How to access result from the previous promise in AngularJS promise chain?

考虑下面的代码 sn-p:

Student.find().then(function(student) {
        return HelpRequest.findByStudent(student);
    }, function(error) { //... }
).then(function(helpRequest) {
    // do things with helpRequest...
    // PROBLEM: I still want access to student. How can I get access to it?
});

在链式承诺中,我想使用我在第一个承诺中得到的student 对象。但正如所写,这无法访问它。我有几个明显的选择:

  1. 将学生存储在外部作用域的变量中(糟糕)
  2. 我实际上不知道这将如何工作,但另一个问题中的解决方案建议我可以在 HelpRequest.findByStudent()Promise.resolve 的结果上调用 then Student.find().then 调用中的组合结果。不过,我认为下面的实现是行不通的。

    Student.find().then(function(student) {
            var data = {student: student};
            HelpRequest.findByStudent(student).then(function(helpRequest) {
                data.helpRequest = helpRequest;
            });
            // PROBLEM: if HelpRequest.findByStudent(student) is asynchronous, how 
            // does this get the data before returning?
            return data; 
        }, function(error) { //... }
    ).then(function(helpRequest) {
        // do things with helpRequest and student
    });
    

我绝对不想处理嵌套在Student.find() 方法中的helpRequest,因为这违背了链接Promise 的目的;即使第二个示例可以工作到可用状态,它仍然感觉像一个 hack。

有没有更好的方法来实现这一点,而不必在我的代码中引入全局状态或嵌套?例如,有没有办法在多个值上调用Promise.resolve(),其中一些可能是承诺,而另一些则不是?

我很好奇,希望我有替代方案/可以理解如何在不引入嵌套或状态的情况下使其正常工作!

【问题讨论】:

  • 你能不能不把第二个promise中的帮助请求连同学生一起返回? return { helpRequest: return HelpRequest.findByStudent(student), student }
  • 我试图找到一个骗子,但我确定我以前回答过这个问题,它可能在蓝鸟问题跟踪器上,所以就是这样。如果有人发现了骗子,请告诉我。

标签: javascript promise ecmascript-6 ecmascript-harmony


【解决方案1】:

在我看来,promise 之禅就是弄清楚它们实际上只是异步值。如果您开始使用它们,这些问题在许多情况下会变得更简单。这不是灵丹妙药,但确实有帮助:

在 ES5 中:

var student = Student.find();
var helpRequest = student.then(HelpRequest.findByStudent);
Promise.all([student, helpRequest]).then(function(results){
    var student = results[0];
    var helpRequest = results[1];
    // access both here
});

在 ES6 中,及其所有功能:

var student = Student.find();
var helpRequest = student.then(HelpRequest.findByStudent);
Promise.all([student, helpRequest]).then(([student, helpRequest]) => {
    // access both here
});

在另一个更丰富的 promise 库(bluebird)中:

var student = Student.find();
var helpRequest = student.then(HelpRequest.findByStudent);
Promise.join(student, helpRequest, function(student, helpRequest){
    // access both here
});

【讨论】:

  • 那么在这个例子中,Student.find() 承诺会被执行两次吗?一次用于HelpRequest.findByStudent() 结果,一次用于Promise.all 方法?它正在启动一个 HTTP 请求,所以这可能不太理想。但也许我误解了,因为这看起来确实很优雅!
  • @OmarDiab 一个promise 代表一个值的代理,该值已经存在。链接到一个承诺不会对其自身发起任何操作 - 它会发出一个 http 请求。 find 方法启动请求 - then 处理程序只让我们在完成后挂钩它的结果。在student 上调用.then 两次与将变量传递给两个不同的函数没有什么不同——它不会执行分配给该变量的代码。
  • 哦,这更有意义。我的承诺心理模型已经失效。太棒了,这绝对可以解决问题:-)
猜你喜欢
  • 1970-01-01
  • 2017-05-16
  • 2021-02-18
  • 1970-01-01
  • 2013-12-08
  • 2015-06-05
  • 2015-11-27
  • 2019-07-09
  • 1970-01-01
相关资源
最近更新 更多