使用 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;
我有另一个函数,然后像这样调用fooService
的update
函数:
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 立即返回一个已解决的承诺的主要内容,如果未能解决你的问题,请参考以下文章