如何判断对象是否是Angular $ q承诺?

时间:2014-03-20 21:57:46

标签: javascript angularjs promise

我的项目中有一个预先存在的非Angular API库。它有一个.request方法,它返回jQuery.Deferred promises。我创建了一个简单的Angular服务,它包装了.request方法,将其结果转换为Angular $ q promise。它看起来像这样:

var module = angular.module('example.api', []);

module.factory('api', function(
    $q,
    $window
) {
    function wrappedRequest() {
        var result = $window.API.request.apply($window.API, arguments);
        return $q.when(result);
    };

    return {
        request: wrappedRequest
    };
});

我想编写一个测试,确保此服务正常运行。它将提供一个带有$window的模拟API,其request方法返回jQuery.Deferred promises。我需要确保生成的对象是Angular $ q promises。


如何确定对象是否是Angular $ q承诺?

对于这个问题中给出的例子,区分jQuery.Deferred promises和Angular $ q promises就足够了,但理想情况下我们可以识别Angular $ q promises。

3 个答案:

答案 0 :(得分:9)

通常,更好的方法是将您拥有的任何对象投射到Angular承诺中。

吸收andables的概念是Promises / A +规范的一部分。大多数承诺库都有办法做到这一点。它允许在promise实现和统一API之间实现令人敬畏的互操作。

为此,$ q使用.when

  

将可能是值的对象或(第三方)包装成$ q承诺。当您处理可能会或可能不是承诺的对象,或者承诺来自不可信任的源时,这非常有用。

它使用了theables的概念将“不可信”的承诺转换为$ q承诺。

所以你要做的就是

var p = $q.when(value); // p is now always a $q promise
                        // if it already was one - no harm

答案 1 :(得分:4)

作为一个部分解决方案,对于给定的示例来说足够和适当,我们可以通过检查特定方法的存在来轻松区分jQuery.Deferred promises和Angular promise。例如,Angular的$ q promises有方法catch来处理错误,而jQuery.Deferred的promises有方法fail

function promiseIsAngularOrJQuery(promise) {
    if (typeof promise.fail === 'function') {
        return 'jquery';
    } else if (typeof promise.catch === 'function') {
        return 'angular';
    } else {
        throw new Error("this can't be either type of promise!");
    }
}

然而,使用这种技术来区分更多不同类型的承诺,或承诺与非承诺之间,可能会变得非常混乱。不同的实现经常使用许多相同的方法名称。它可能会起作用,但我不会走那条路。


有一种替代方案应该能够在合理的条件下可靠地识别$ q promises:在非恶意环境中对可信对象进行操作,只使用单个版本的Angular。但是,有些人可能会认为它太“黑”而无法认真使用。

如果使用String()函数将函数转换为字符串,则结果是该函数的源代码。我们只需要使用它来将潜在promise对象的.then方法与已知$ q promise对象的.then方法进行比较:

function isAngularPromise(value) {
    if (typeof value.then !== 'function') {
        return false;
    }
    var promiseThenSrc = String($q.defer().promise.then);
    var valueThenSrc = String(value.then);
    return promiseThenSrc === valueThenSrc;
}

答案 2 :(得分:1)

我目前的解决方案是使用instanceof

var AngularPromise = $q.resolve().constructor;

console.log($q.resolve() instanceof AngularPromise);  // true

如果对象确实是Angular Promise,则保证返回true。

演示:https://jsfiddle.net/DerekL/cmzp7ovj/