如何测试函数是否在Ember中返回一个promise?

时间:2015-01-31 02:01:53

标签: ember.js rsvp.js

在Ember中,我有时遇到需要检查函数是否返回承诺的情况。例如,如果我有一个派生的路线:

MyRoute = ParentRoute.extend({
  beforeModel: function() {
    this._super().then(function() {
      // do something...
    });
  }
});

但是虽然beforeModel可以返回一个承诺,但它可能不会。特别是,如果它是默认的Ember.K实现,那么它就没有了。我并不总是这么做:

var res = this._super();
if (typeof res.then === "function") {
  res.then(function() {
    // do X
  });
} else {
  // do X
}

我认为有一种方法可以包装一些人不知道它是否是一个可用的东西,然后无论如何链。但是我无法在文档中找到它。

以上是不可取的,因为它很冗长,需要两次代码。

思想?

更新

我能够通过以下coffeescript测试确认@ torazaburo的回复:

`import { test, module } from 'ember-qunit'`

module "testing promise behavior"

test "can cast to promise", ->
  expect 3
  order = []
  returnsPromise = ->
    new Ember.RSVP.Promise (resolve) ->
      order.push 'a'
      resolve('response 1')
  returnsValue = ->
    order.push 'b'
    'response 2'

  Ember.run ->
    Ember.RSVP.resolve(returnsPromise()).then (response) ->
      order.push 'c'
      equal response, 'response 1'
    Ember.RSVP.resolve(returnsValue()).then (response) ->
      order.push 'd'
      equal response, 'response 2'

  equal order.join(' '), 'a b c d'

感谢您的解决方案!似乎RSVP的Promises实现也有一个内置的解决方法,可以按照你的建议进行,结果与cast相同,正如你的建议,现在已经弃用了。

1 个答案:

答案 0 :(得分:7)

可能还有其他更好的方法,但你可以这样做:

function ensurePromise(x) {
    return new Ember.RSVP.Promise(function(resolve) {
        resolve(x);
    });
}

如果x不是承诺,则返回已使用该值实现的承诺,然后您可以暂停then。如果x 是承诺,则会返回承诺,承诺其状态(包括已解决/拒绝状态和值/原因)。

这相当于本机承诺

Promise.resolve(x)

所以在你的情况下,

MyRoute = ParentRoute.extend({
    beforeModel: function() {
        ensurePromise(this._super()).then(function() {
            // do something...
        });
    }
});

但请注意,这可能会将同步值转换为异步值(承诺)。但是,通常认为在某些情况下具有同步行为而在其他情况下异步行为的函数是不好的做法。所以似乎没问题,在这种情况下,我们有一个可能是同步异步的值,将它强制转换成总是异步的东西。

我相信在过去的某个版本中曾经有一种名为RSVP.Promise.cast的东西,我似乎记得这件事大致相同,但我现在无法追踪它。