Angular的$q.when如何工作?

104

有人能解释一下 AngularJS 中的 $q.when 是如何工作的吗?我正在分析 $http 的工作原理,发现了这个:

var promise = $q.when(config);

以下是来自Chrome控制台的配置对象:

Object {transformRequest: Array[1], transformResponse: Array[1], cache: Object, method: "GET", url: "/schedule/month_index.html"}
cache: Object
headers: Object
method: "GET"
transformRequest: Array[1]
transformResponse: Array[1]
url: "/schedule/month_index.html"
__proto__: Object

接下来会发生什么?这个对象会如何被解决或拒绝?


$q 实现了 Promise 模式,它只是 JavaScript 回调的简单包装器。因此,当回调成功触发时,Promise 就会被解决。 - Ajay Beniwal
1
@Ajaybeniwal,在这种情况下是传递对象而不是回调函数。当传递对象时,如何解决/拒绝? - SET001
2个回答

117

当调用 $q.when 时,如果传入的是一个 promise 或其他类型的值,它会将传入的值包装成一个 promise 并调用 resolve。如果你向其传递了一个值,则该值永远不会被拒绝。

来自文档:

将可能是值或(第三方)thenable promise 的对象封装成 $q promise。当你处理可能是 promise 或不是 promise 的对象时,或者 promise 来自于一个不可信的源时,这很有用。


如果您传递一个值给它 - 那么如果我传递对象呢? - SET001
13
价值、对象、数组都是一样的。 - Derek Ekins
3
如果我传递一个返回 Promise 的函数,那么它的 then 回调函数是否会接收到由 resolve 发送的 Promise 结果参数? - Onur Topal
3
当你说“传递函数”时,是指作为函数对象进行传递:$q.when(myfunc),还是通过调用传递的函数进行传递:$q.when(myfunc())?我不确定前者会做什么...后者将首先调用 myfunc(),然后将返回的 promise|value 传递给 .when() - jrista

0

我知道这个问题很老了,而且已经有一个很好的答案了,但是还有很多后续问题,我想整合一些答案,即使只是作为自己的参考。

"这个对象是如何被解析或拒绝的?"

$q.when返回一个Promise对象。要获取Promise的解决值,请使用promise .then(callbackFunction)语法...

let i = 1;
$q.when(i).then(function(resolvedValue){
    console.log(resolvedValue === i);
});

在这里了解更多 关于 Promises 的信息

"如果我传递对象,而不是值怎么办?"

当你传递的不是 Promise/"then-able",比如整数、字符串、数组、对象甚至函数时,其行为相同。以下是一些例子:

// an object...
let o = {name:'Nate'};
$q.when(o).then(function(resolvedValue){
     console.log(resolvedValue === o);
});
//...an array...
let a = ['Nate'];
$q.when(a).then(function(resolvedValue){
     console.log(resolvedValue === a);
});

"如果我传递一个返回 Promise 的函数会怎样?"

如果您传递一个未执行的函数,它就像传递任何其他对象一样,除了 Promise;resolvedValue 将等于函数本身,而不管函数的返回值如何。

let i = 1;
let f = function(){ return Promise.resolve(i); };
$q.when(f).then(function(resolvedValue){
     // the resolvedValue is the *function* `f` itself!...
     console.log(resolvedValue === f);

     // the resolvedValue is NOT the function's return value, even if the function returns a Promise
     console.log(resolvedValue !== i);
});

先调用函数 $q.when(func)$q.when(func())

正如@jrista所说,如果你有一个返回 Promise 的函数,并且在将其传递给 $q.when 之前调用该函数,那么你实际上只是将一个 Promise 传递到了 $q.when 中。

let i = 1;
let f = function(){ return i; };
$q.when(f); /* the resolved value will be the function `f` itself */
$q.when(f()); /* the resolved value will be based on the function `f`'s  return value (the function `f` is no longer relevant, because you called it*/

$q.when(func) vs $q.when(..).then(func)

注意不要混淆将函数传递到Promise / $q.when(f)中的情况(在这种情况下,Promise的解析值将等于该函数):

let f = function(){ /*...*/ };
$q.when(f)

与使用 .then() 中的函数相比(在这种情况下,该函数将被执行并传递 Promise 的已解决值):

let f = function(){ /*...*/ };
$q.when(/*...*/).then(f);

如果我传递一个 Promise/"then-able" 会怎样?

正如文档和其他答案所述,传递一个 Promise 对象或任何“then-able”是特殊的。与其解析为相同的 Promise 对象$q.when 将解析为 Promise 的已解决值

let i = 1;
let p = Promise.resolve(i); 
$q.when(p).then(function(resolvedValue){
     // the resolvedValue is *NOT* the promise `p` itself...
     console.log(resolvedValue !== p);

     // the resolvedValue **IS* the promise's *resolved* value:
     console.log(resolvedValue === i);
});

为什么要使用$q.when

正如文档所述

当你处理一个可能是或可能不是promise的对象,或者promise来自于一个不可信的来源时,它非常有用。

一致的返回类型

让我们举个“可能是或可能不是promise的对象”的例子;也许您缓存了$http()的结果。现在,您可以编写一个函数,该函数返回缓存的值,或者返回异步的$http()请求以获取该值。

var cache = {};
var get_value_from_cache_or_$http_get = function (resource_id){
    var cached_value = cache[resource_id];
    if (cached_value){
        // if you cached the value, you don't need to make another $http request...
        // HOWEVER you still want to return a Promise/then-able, 
        // so the code calling your function `get_value_from_cache_or_$http_get` 
        // gets a consistent return type (i.e. something "then-able")
        return $q.when(cached_value);
    } else {
        return $http.get(resource_id);
    }
}

现在函数get_value_from_cache_or_$http_get始终返回一个"then-able",无论它是否获取了一个promise(即$http.get),或者可能是一个不是promise的值(即从cache中获取,但包装在$q.when中)

$scope在UI中的更新

我认为文档中的这部分特别重要(也许是我使用$q.when的最重要原因)...

$q与AngularJS中的$rootScope.Scope Scope模型观察机制集成,这意味着更快地将解析或拒绝传播到您的模型中,并避免不必要的浏览器重绘,从而导致UI闪烁。

换句话说,我发现当我获取一个普通 Promise 的解析值并分配给 $scope 时,我不总是立即在 UI 中看到变化(我必须等待下一个 $digest())。
let p = Promise.resolve('update');
p.then(function(resolvedValue){ $scope.val = resolvedValue; })

如果我将Promise包装在$q.when,则一旦解析的值被分配给$scope,我就会立即看到UI中的更改。
let p = Promise.resolve('update');
$q.when(p).then(function(resolvedValue){ $scope.val = resolvedValue; })

$q.when$q.resolve

注意这两个函数是相同的:$q.when === $q.resolve,正如文档所说

[$q.resolve 是] when 的别名,以保持与 ES6 命名一致。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接