【问题标题】:How do I create a class that processes two promises and then returns a promise?如何创建一个处理两个承诺然后返回一个承诺的类?
【发布时间】:2017-07-06 11:20:17
【问题描述】:

我想创建一个类,其职责是轮询数据源,将信息整理到一个“警报”对象数组中,然后将这些警报的子集传递给需要它们的任何其他类。

因为轮询是异步发生的(我正在从 Web 服务请求数据),所以我假设我实际需要返回的是一个 promise,它在实现时会给出正确的 Alert 子集对象。

但显然我不明白该怎么做,因为应该返回承诺的方法会返回其他东西。

到目前为止,这是我的代码。如您所见,我试图将承诺存储在实例属性中,然后检索它:

export class AlertCollection {

  constructor() {
    this.alerts = null;
  }

  // poll the data sources for alert data; store a promise that resolves
  // to an array of alerts
  poll() {
    this.alerts = this.pollTeapot()
                    .then( (arr) => {this.pollDeliverance(arr);} );

  }                                                                                                  

  // return a promise that fulfils to an array of the alerts you want
  filteredAlerts(filter) {
    return this.alerts; // not filtering for now
  }                                                                                                  

  // return a promise that fulfills to the initial array of alerts
  pollTeapot() {

    let process = (json) => {
      json2 = JSON.parse(json);
      return json2.map( (a) => new Alert(a) );
    };                                                                                               

    message = new MessageHandler("teapot", "alerts")
    return message.request().then( (json) => {process(json);} );
  }

  // Modify the alerts based on the response from Deliverance.
  // (But for the time being let's not, and say we did.)
  pollDeliverance(alerts) {
    return alerts;
  }

}

message.request() 从 Web 服务返回一个承诺。这样可行。如果我对pollTeapot() 中的process 函数进行快照,我会得到正确的数据。

但是,如果我对来自filteredAlerts() 的返回值进行快照,我就不明白了。我也没有得到 null (这至少是有道理的,尽管它是错误的。)我得到类似 { _45: 0, _81: 0, _65: null, _54: null } 的东西。

在这一点上,任何指针都会非常感激。 (顺便说一句,这是在 React Native 中,如果有帮助的话。)

【问题讨论】:

  • 我得到了你的问题,但你的标题提到处理 2 个承诺,我看不出那是哪里 - AFAICS 你只是在处理一个 - message.request()
  • 如果你想链接 Promise,你应该看看 ES6 中的Promise.all()
  • @Jamiec 在poll() 我链接pollTeapot() 然后pollDeliverance();你是对的,目前后者没有做任何事情,但如果我不能让它为一个人工作,那么添加另一个人没有多大意义......
  • @AndyJones 啊,我看到pollDeliverance 进行了另一个 异步调用并更新了Alert 的?
  • @Hinrich -- 如果我理解正确,Promise.all() 会同时调用这两个服务吗?我不想那样。

标签: javascript react-native es6-promise


【解决方案1】:

我不确定我是否完全理解了您的问题,但我会尝试为您提供一个通用的解决方案来一个接一个地链接承诺。

someAsyncFunction().then(dataFromAsync1 => {
    return anotherAsyncFunction(dataFromAsync1).then(dataFromAsync2 => {
        return doSomethingWithData(dataFromAsync1, dataFromAsync2);
    });
});

【讨论】:

  • 你需要记住 return 来自 then 内的回调,否则你将无法链接
【解决方案2】:

这将很难描述 - 我有一个工作示例,但令人费解的是我不得不“模拟”所有异步部分,并使用 function 类而不是 @987654324 @关键字 - 但想法是一样的!


这个答案有两部分。

  1. alerts 存储为实例变量没有意义。它们是异步的,直到异步调用完成后才会存在

  2. 您需要将所有行为链接到对poll的初始调用


一般来说,您可以像这样将承诺链接在一起

functionWhichReturnsPromise()
      .then(functionPointer)
      .then(function(result){
           // some functionality, which can return anything - including another promise
      });

所以你的代码最终看起来像

var alertCollection = new AlertCollection()
alertCollection.poll().then(function(alerts){
    //here alerts have been loaded, and deliverance checked also!
});

该类的代码如下所示:

export class AlertCollection {

  constructor() {
  }

  // poll the data sources for alert data; store a promise that resolves
  // to an array of alerts
  poll() {
    return this.pollTeapot()
               .then(filteredAlerts)
               .then(pollDeliverance);

  }                                                                                                  

  // return a promise that fulfils to an array of the alerts you want
  filteredAlerts(alerts) {
    return alerts; // not filtering for now
  }                                                                                                  

  // return a promise that fulfills to the initial array of alerts
  pollTeapot() {

    let process = (json) => {
      json2 = JSON.parse(json);
      return json2.map( (a) => new Alert(a) );
    };                                                                                               

    message = new MessageHandler("teapot", "alerts")
    return message.request().then(process);
  }

  // Modify the alerts based on the response from Deliverance.
  // (But for the time being let's not, and say we did.)
  pollDeliverance(alerts) {
    return alerts;
  }

}

一些笔记

  • filteredAlerts 可以为所欲为,只要返回结果数组即可
  • pollDeliverance 也可以为所欲为 - 如果它需要调用另一个异步方法,请记住返回一个解析为警报数组的承诺 - 可能会根据异步调用的结果进行更新。

我创建了一个 JSFiddle 来演示这一点 - 使用一个简单的 getJSON 调用来复制其中一些的异步性质。正如我所提到的,它很复杂,但演示了这个过程:

现场示例:https://jsfiddle.net/q1r6pmda/1/

【讨论】:

  • 这里的问题是我需要能够多次调用filteredAlerts() 才能在返回的结果上获得不同的过滤器。我不想每次都轮询数据源。这就是为什么我想要一个有自己状态的类;没有它,我认为上课没有什么意义,真的。
  • @AndyJones 那是我的错误,我应该更改参数并从您的原始返回(请参阅更新的答案)。基本上,参数 isAlert 实例 - 您可以以任何您喜欢的方式过滤和返回该数组。请参阅我的现场示例,我正是这样做的
  • 听起来好像您在说我不能拥有一个轮询一次并多次提供承诺的类。这是一个地狱般的限制。 (我的想法是存储承诺,而不是实际结果。)
  • @AndyJones 我不确定我是否跟随。您当然可以缓存 promise 的结果,但不要期望它在异步解决之前就在那里。您将非常接近这里最喜欢的欺骗关闭问题stackoverflow.com/questions/6847697/… 无论如何,这是一个很难回答的问题,而且非常复杂。如果您愿意,请随时在聊天中 ping 我! (刚出去吃午饭,所以可能会在 20 分钟内没有反应)
猜你喜欢
  • 2015-11-27
  • 2015-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 2016-07-20
相关资源
最近更新 更多