我非常喜欢承诺被自动包装的干净(并且我认为易于遵循)方式:
$scope.myData = DataService.query({something:"etc"}); // done;
Run Code Online (Sandbox Code Playgroud)
而且我真的不关心现在这样做的标准方法,没有自动解包:
DataService.query({something:"etc"}).$promise.then(function (data){
$scope.myData = data;
});
Run Code Online (Sandbox Code Playgroud)
我想看到的是这样的:
$scope.pulseData = $scope.setPromise(CitsciAnalytics.pulse({
projId:"yardmap"
}));
Run Code Online (Sandbox Code Playgroud)
但我看不出如何实现这一目标.我得到的最接近的是:
$scope.pulseData = $scope.setPromise("pulseData", CitsciAnalytics.pulse({
projId:"yardmap"
}));
Run Code Online (Sandbox Code Playgroud)
使用添加到根范围的函数:
.run(["$rootScope", "$log", function ($rootScope, $log) {
//parent method to avoid promise unwrapping boilerplate
$rootScope.setPromise = function (scopeVar, promise) {
if (arguments.length === 2 && promise && promise.$promise) {
var scope = this;
promise.$promise.then(function (data){
scope[scopeVar] = data;
});
} else {
$log.error("$rootScope.setPromise has invalid arguments");
}
};
}]);
Run Code Online (Sandbox Code Playgroud)
但我不喜欢unDRY要求必须将范围变量名称作为附加字符串传递.有没有其他人解决这个问题,或者看到一种方法更干净地做到这一点?
我正在尝试为返回角度承诺($ q库)的方法编写测试.
我不知所措.我正在使用Karma运行测试,我需要弄清楚如何确认该AccountSearchResult.validate()函数返回一个promise,确认promise是否被拒绝,并检查使用promise返回的对象.
例如,正在测试的方法具有以下(简化):
.factory('AccountSearchResult', ['$q',
function($q) {
return {
validate: function(result) {
if (!result.accountFound) {
return $q.reject({
message: "That account or userID was not found"
});
}
else {
return $q.when(result);
}
}
};
}]);
Run Code Online (Sandbox Code Playgroud)
我以为我可以这样写一个测试:
it("it should return an object with a message property", function () {
promise = AccountSearchResult.validate({accountFound:false});
expect(promise).to.eventually.have.property("message"); // PASSES
});
Run Code Online (Sandbox Code Playgroud)
这传递了,但这也是错误的(错误的):
it("it should return an object with a message property", function () {
promise = AccountSearchResult.validate({accountFound:false});
expect(promise).to.eventually.have.property("I_DONT_EXIST"); // PASSES, should fail
}); …Run Code Online (Sandbox Code Playgroud) 目标
我正在尝试创建一系列承诺"增强器",它们将围绕现有的承诺(简单的http请求)添加功能(如缓存,排队,重定向处理等).
问题
我正在通过这种增强承诺的方法遇到的问题是,如果增强功能将任何功能或公共可访问的属性添加到承诺中(或者如果我正在包装已经增强的承诺,例如一个重复的请求),那么当我通过返回一个新的包装它在一个新的承诺$q.
题
我可以使用什么模式来增强或包装承诺(如下面的两个示例中所示),但不会丢失承诺可能具有的任何其他(非冲突)增强功能?
例1
这是一个自动处理503-Retry-After错误的示例:
function _enhancePromiseWithAutoRetry(promise) {
var enhancedPromise = $q(function(resolve, reject) {
var newReject = get503Handler(this, resolve, reject);
promise.then(resolve, newReject);
});
// 503 handling isn't enabled until the user calls this function.
enhancedPromise.withAutoRetry = function(onRetry, timeout) {
var newPromise = angular.copy(this);
newPromise._503handled = true;
newPromise._503onRetry = onRetry;
newPromise._503timeout = timeout;
return newPromise;
};
return enhancedPromise;
}
Run Code Online (Sandbox Code Playgroud)
我的想法是,如果我返回使用上述功能增强的承诺,用户可以:
someRequest.withAutoRetry().then(onSuccess, onError);
Run Code Online (Sandbox Code Playgroud)
或者更清楚(带链接):
someRequest.then(onSuccess, onAnyError)
.withAutoRetry().then(onSuccess, onNon503Error);
Run Code Online (Sandbox Code Playgroud)
这里,then(...)如果服务器繁忙,第一次调用可能会立即出错,但之后的调用.withAutoRetry()会在重复请求之前轮询服务器,直到响应成功,或者RetryAfter返回非错误.
例2
这是另一个添加自定义缓存行为的示例: …
如果我使用$ interval创建一个promise,它是可取消的请参阅:http://jsbin.com/jeweke/2/
timer = $interval(intervalFunc, intervalDelay, 10);
timer.then(
function(res) {console.log('ok', res);},
function(err) {console.log('err', err);}
);
Run Code Online (Sandbox Code Playgroud)
但是,如果我将承诺链接起来,则返回的承诺不可取消.见:http://jsbin.com/jeweke/1/
timer = $interval(intervalFunc, intervalDelay, 10)
.then(
function(res) {console.log('ok', res);},
function(err) {console.log('err', err);}
);
Run Code Online (Sandbox Code Playgroud)
是什么赋予了?这是它应该如何工作吗?
注意 - 这里的例子很容易改编自http://jsfiddle.net/ExpertSystem/fZc3W/
我在尝试重试功能时遇到了一些麻烦,希望得到一些帮助.我有一个我想要调用的$资源,直到成功条件发生或超过最大重试次数.
我似乎遇到的问题是,在我的重试功能中,我正在调用另一个承诺,这就是检查条件的地方.我可以通过删除添加的承诺并在几次重试后创建默认成功条件来使代码按预期运行,但我无法弄清楚如何正确地将新的promise调用添加到函数中.
resource 是一个Angular $资源的替身,它返回$ promise
我的代码如下:
resource.$promise.then(function (response) {
return keepTrying(state, 5);
}).then(function (response) {
}).catch(function (err) {
console.log(err);
});
Run Code Online (Sandbox Code Playgroud)
而keepTrying功能:
function keepTrying(state, maxRetries, deferred) {
deferred = deferred || $q.defer();
resource.$promise.then(function (response) {
success = response;
});
if (success) {
return deferred.resolve(success);
} else if (maxRetries > 0) {
setTimeout(function () {
keepTrying(state, maxRetries - 1, deferred);
}, 1000);
} else if (maxRetries === 0) {
deferred.reject('Maximum retries exceeded');
}
return deferred.promise;
}
Run Code Online (Sandbox Code Playgroud) 我正在开发一个angularJS应用程序,这是我使用这个框架的第一个网站.在我的应用程序中,我需要在for循环中进行$ http调用.在下一次迭代之前的循环中,我想等待前一次调用的响应.什么是最好和最简单的方法来做到这一点.我已经尝试过使用callBack,$ q.all(),. then在所有这些中只有最后一个请求正在通过.请帮忙.
注意:我通过$ http调用的API无法对请求进行排队.
编辑: 我已经尝试了以下两种方法,在这两种情况下,只有最后一个请求成功.你能告诉我我在这里做错了吗?
方法1:
var promiseArray=[];
for(var i=0;i<items.length;i++)
{
var promise=services.Post(items[i]);
promiseArray.push(promise);
}
$q.all(promiseArray).then(data)
{
...
}
Run Code Online (Sandbox Code Playgroud)
方法2:
var promises = [];
for (var i = 0; i < items.length; i++) {
var deffered = $q.defer();
var promise = services.Post(items[i]);
promise.success(function(data) {
deffered.resolve(data);
})
promises.push(deffered);
}
Run Code Online (Sandbox Code Playgroud)
var result = $ q.all(promises);
编辑:2 服务代码:
Services.Post = function(lineItemId, submitUrl) {
var url = (submitUrl) ? submitUrl : Services.serviceUrl;
return $http.post(url, {
"LineItemID": lineItemId
}).
success(function(data, status, headers, …Run Code Online (Sandbox Code Playgroud) 我有一个承诺SharedData,它也返回一个变量服务.template.值为mytemplate,我构建了一个url,我将传递给templateUrl指令,但没有成功.
app.directive('getLayout', function(SharedData) {
var buildUrl= '';
SharedData.then(function(service) {
buildUrl = service.template + '/layouts/home.html';
console.log(buildUrl); // return mytemplate/layouts/home.html which is the URL I want to use as templateUrl
});
return {
restrict: 'A',
link: function(scope, element, attrs) {...},
templateUrl: buildUrl
}
});
Run Code Online (Sandbox Code Playgroud)
谢谢你的帮助!
相关的小提琴:https: //jsfiddle.net/tqf4zea7/1/
我在角度控制器中使用$ q.为了测试某些场景,我在作用域上创建了一个数组,用于将消息推送到:
$scope.messages = [];
Run Code Online (Sandbox Code Playgroud)
我已经设置了一个返回$ q函数的函数,如下所示:
function returnAPromise(valToReturn){
return $q(function(resolve, reject){
$timeout(function(){
resolve(valToReturn);
}, 500);
});
}
Run Code Online (Sandbox Code Playgroud)
然后我.then()调用结果看起来像这样:
returnAPromise('third').then($scope.messages.push);
Run Code Online (Sandbox Code Playgroud)
因为我只想将promise的解析值推送到数组,我想我可以传递messages数组的push方法,但是当我这样做时,我收到以下错误:
VM289 angular.js:12520 TypeError: Array.prototype.push called on null or undefined
at processQueue (VM289 angular.js:14792)
at VM289 angular.js:14808
at Scope.$eval (VM289 angular.js:16052)
at Scope.$digest (VM289 angular.js:15870)
at Scope.$apply (VM289 angular.js:16160)
at VM289 angular.js:17927
at completeOutstandingRequest (VM289 angular.js:5552)
at VM289 angular.js:5829
Run Code Online (Sandbox Code Playgroud)
如果我将push包含在函数中,它可以正常工作:
returnAPromise('third').then(function(message){
$scope.messages.push(message)
});
Run Code Online (Sandbox Code Playgroud)
这是一个我不明白的封闭问题吗?
我开始使用angular中的promises来解析我的api调用,使用以下语法:
$scope.module = moduleFactory.get({id: $stateParams.id})
.$promise.then(function(response){
$scope.module = response;
}
Run Code Online (Sandbox Code Playgroud)
现在,我遇到了一种情况,我必须在for循环中链接多个promise,并在for循环中的所有promise都已解析后执行一些代码.我一直试图用$ promise语法搜索如何做到这一点,但互联网上的大多数消息来源都在谈论$ q.我是开发工作的新手,我发现在这两个概念($ q和$ promise)之间徘徊是非常困惑的.请你好心人:首先,向我解释$ promise和$ q之间的区别; 第二,如果我决定使用$ q来解决我上面描述的当前问题,是否意味着我将不得不重写使用$ promise的代码,以使其可以像$ q.all()那样进行链接?
我正在开发Spotify应用程序.我能够登录并获取我的令牌.我的问题是我无法访问方法之外的变量.在这种情况下"getCurrentUser"
这是我的方法:
function getUser() {
if ($localStorage.token == undefined) {
throw alert("Not logged in");
} else {
Spotify.getCurrentUser().then(function(data) {
var names = JSON.stringify(data.data.display_name);
console.log(names)
})
}
};
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我在控制台上记录了名称,并且我在控制台中获得了正确的值.但是只有在我调用函数时getUser()才能在那里工作,undefined即使返回了names变量.
我需要$scope那个变量.
angular-promise ×10
angularjs ×10
javascript ×5
promise ×4
angular-http ×1
chai ×1
jasmine ×1
restangular ×1
timeout ×1