使用 AngularJS 立即返回一个已解决的承诺

Posted

技术标签:

【中文标题】使用 AngularJS 立即返回一个已解决的承诺【英文标题】:Immediately return a resolved promise using AngularJS 【发布时间】:2014-09-07 18:53:41 【问题描述】:

我正在努力理解 javascript(尤其是 AngularJS)中的承诺。

我在服务中有一个函数,我们称之为fooService,它检查我们是否加载了一些数据。如果有,我只希望它返回,如果没有,我们需要加载数据并返回一个 Promise:

this.update = function(data_loaded) 
    if (data_loaded) return;  // We've loaded the data, no need to update

    var promise = Restangular.all('someBase').customGet('foo/bar').then(function(data) 
        // Do something with the data here
    

    return promise;

我有另一个函数,然后像这样调用fooServiceupdate 函数:

fooService.update(data_loaded).then(function() 
    // Do something here when update is finished
)

我的问题是,如果我们不需要在 update 函数中加载数据,则不会返回承诺,因此在我的其他函数中不会调用 .then()。这里应该采用什么方法 - 基本上,如果我们不需要从 Restangular 调用中获取数据,我想立即从 update() 函数返回已解决的承诺?

【问题讨论】:

【参考方案1】:

由于您的 promise 使用与 JavaScript 原生语法相同的语法,您可以使用并返回已解析的 JavaScript promise:Promise.resolve()

return(Promise.resolve("MyReturnValue"));

【讨论】:

这就是我想要的答案;我有一个价值;它已经准备好了,我只想将它包装在 Promise 中以满足期望 Promises 的 API ... Promise ,我立即解决了(用文字)“ 这也是我想要的。我有一个对象,只需要返回一个承诺,因为这是 API 所期望的。 注意这个答案的 IE 支持。 $q 提供跨浏览器支持 @JosefE.,关于 IE 支持的要点。理想的答案将解决现代 Javascript 案例(在现代浏览器中或使用转译器)和遗留案例。让我们向微软诸神祈祷,IE 很快就会过时。【参考方案2】:

当前接受的答案过于复杂,滥用deferred anti pattern。这是一个更简单的方法:

this.update = function(data_loaded) 
    if (data_loaded) return $q.when(data);  // We've loaded the data, no need to update

    return Restangular.all('someBase').customGet('foo/bar')
                             .then(function(data) 
        // Do something with the data here 
    );
;

或者,更进一步:

this._updatep = null;
this.update = function(data_loaded)  // cached
    this._updatep = this._updatep || Restangular.all('someBase') // process in
                                                .customGet('foo/bar'); //.then(..
    return this._updatep;
;

【讨论】:

感谢您的提示。我总是错过Kris Kowal's Q 的Q(initialVal) 语法,应该知道$q.when(data) 可以做同样的伎俩。【参考方案3】:

AngularJS 的$q 服务将在这里为您提供帮助。它很像Kris Kowal's Q promise 库。

当您有一个可能返回承诺或值的异步方法时,请使用$q.when 方法。它将接受传递给它的任何内容,无论是承诺还是值,并创建一个承诺,该承诺将根据传递的承诺被解析/拒绝,或者如果传递了值则被解析。

$q.when( fooService.update(data_loaded) ).then(function(data)
   //data will either be the data returned or the data
   //passed through from the promise
)

然后在你的更新函数中返回数据而不是仅仅返回

if (data_loaded) return data_loaded;

【讨论】:

【参考方案4】:

类似于Elo's answer,您可以使用 async/await 语法返回已解决的承诺:

this.update = async (data_loaded) => 

    if (data_loaded) 
        return await null;  // Instead of null, you could also return something else
                            // like a string "Resolved" or an object  status: 200 
    else 
        return await OtherPromise();

【讨论】:

【参考方案5】:

您可以像这样使用$q.defer()

this.update = function (data_loaded) 
    var deferred = $q.defer();

    if (data_loaded) 
        deferred.resolve(null); // put something that your callback will know the data is loaded or just put your loaded data here.
     else 
        Restangular.all('someBase').customGet('foo/bar').then(function(data) 
            // Do something here when update is finished
            deferred.resolve(data);
        
    

    return deferred.promise;
;

希望这会有所帮助。

【讨论】:

我不知道这是怎么被两次投票的,这是延迟反模式,可以大大简化。 这不仅是延迟的反模式,它也无法传播错误。 @Benjamin 恕我直言,这与延迟反模式不完全相同。您提到的延迟反模式是可以完全删除延迟而不会丢失功能。但是,是的,您的答案要简单得多,并且可以很好地处理错误。 @samtuner 请接受本杰明的回答而不是这个。 @Bergi imo 此解决方案的最大问题是,如果在返回数据之前多次调用此方法,它将发出多个请求而不是一个请求,因为数据被缓存而不是承诺,并且没有“已发送”标志。错误处理也是一个大问题,所以你就在那里。

以上是关于使用 AngularJS 立即返回一个已解决的承诺的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 测试 - 来自服务的承诺无法解决

如何在angularjs中链接promise错误函数

将 D3 注入 AngularJS 的正确约定

如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务?

承诺已解决但返回部分数据 - 其余“未定义”

创建一个立即解决的“空”承诺