我有用于检查与服务器的连接的代码。我的代码每60秒运行一次。代码运行后,它会创建一条消息,并显示在页面上。这是我到目前为止所做的:
检查的代码:
$interval(function () {
us.isConnected().then(closeConnect, openConnect);
}, 60 * 1000);
执行检查的代码
isConnected = (): ng.IPromise<any> => {
var self = this;
var deferred = this.$q.defer();
this.$http({
method: 'GET',
url: self.ac.baseUrl + '/api/Connect/Verify'
})
.success(() => {
self.connects = 0;
self.connectMessage = null;
deferred.resolve();
})
.error(() => {
if (self.connects == 0) {
self.connectMessage = "Unable to establish a connection to the server. " + retryMessage();
} else if (self.connects == 1) {
self.connectMessage = "Unable to establish a connection to the server for " + self.connects + " minute" + retryMessage();
} else {
self.connectMessage = "Unable to establish a connection to the server for " + self.connects + " minutes." + retryMessage();
}
self.connects++;
deferred.reject();
});
return deferred.promise;
};
我想做的是有一个名为retryMessage()的简单函数,它允许我给出这样的消息:
Unable to establish a connection to the server for 164 minutes.
Connection will be retried in 59 seconds.
Unable to establish a connection to the server for 164 minutes.
Connection will be retried in 58 seconds.
Unable to establish a connection to the server for 164 minutes.
Connection will be retried in 57 seconds.
...
Unable to establish a connection to the server for 164 minutes.
Connection will be retried in 1 seconds.
Unable to establish a connection to the server for 164 minutes.
Retrying connection now.
Unable to establish a connection to the server for 165 minutes.
Connection will be retried in 59 seconds.
当重新检查时,向下计数秒数直到0。
任何人都可以在AngularJS中建议我可以实现这个倒计时吗?
答案 0 :(得分:9)
执行您尝试的操作的一种可能方法是将$q.notify
与$interval
结合使用。
其他消息可以通过解析和拒绝传递。当然,任何这样做的地方你都可以直接打印到日志记录服务,但我认为将这些消息与promise行为一起返回可能是合适的(如果你愿意的话,你甚至可以返回一个完整的对象)状态代码和其他数据以及消息)。
在下面的示例中,我让控制器管理日志记录并将其输出限制为12行。我还为连接测试指定了参数,因此它尝试连接每60秒,20次(这些参数可以更改为尝试不同的间隔,不同的次数或无限期)。如果测试失败,它会每秒打印重试消息,直到重试尝试:
(function() {
"use strict";
var myApp = angular.module('myApp', []);
myApp.controller('MainController', ['$scope', 'us', '$log', MainController]);
myApp.service('us', ['$interval', '$q', '$http', '$log', usService]);
/* Controller */
function MainController($scope, us, $log) {
var _data = {
connectLog: null
},
_connectMessages = [],
_MAX_LOG_LINES = 12;
$scope.data = _data;
_log("Starting connection test...");
us.testConnection(60, 20) //60 seconds between tests, 20 tests (if no max specified, could run forever...)
.then(onTestsSuccessful, onTestsFailed, onNotifying);
function onTestsSuccessful(result) {
_log(result);
// do success stuff...
}
function onTestsFailed(result) {
_log(result);
// do failed stuff...
}
function onNotifying(result) {
_log(result);
//do retrying stuff...
}
function _log(message, deferOutput) {
//$log.debug(message);
_connectMessages.push(message);
if (_MAX_LOG_LINES && _connectMessages.length > _MAX_LOG_LINES) {
_connectMessages.splice(0, _connectMessages.length - _MAX_LOG_LINES);
}
if (!deferOutput) {
_data.connectLog = _connectMessages.join('\n');
}
}
}
/* Service */
function usService($interval, $q, $http, $log) {
var _testConnectionInterval,
_testsRun;
return {
testConnection: _startTestConnection
};
function _startTestConnection(secondsBetweenTests, maxTests) {
var deferred = $q.defer(),
connectAttempts = 0;
_cancelConnectionTest();
_connectionTest().then(onConnectionTestSuccess, onConnectionTestFail); //immediately do first test
_testsRun++;
if (secondsBetweenTests > 0) {
_testConnectionInterval = $interval(
function repeatConnectionTest() {
if (maxTests && _testsRun >= maxTests) {
return _cancelConnectionTest();
}
deferred.notify("Retrying connection now.");
_connectionTest().then(onConnectionTestSuccess, onConnectionTestFail);
_testsRun++;
},
secondsBetweenTests * 1000); //start the countdown to the next
}
function onConnectionTestSuccess(result) {
connectAttempts = 0;
if ((maxTests && _testsRun >= maxTests) || !secondsBetweenTests) {
deferred.resolve("Last connection test success, " + _testsRun + " tests complete.");
} else {
deferred.notify("Connection test success.");
}
}
function onConnectionTestFail(result) {
var minutesPassed = connectAttempts * secondsBetweenTests / 60,
minutesRoundedToTwoDec = +(Math.round(minutesPassed + "e+2") + "e-2");
var connectMessage = "Unable to establish a connection to the server" + (connectAttempts === 0 ? "." : " for " + minutesRoundedToTwoDec + " minute" + (minutesPassed > 1 ? "s." : "."));
connectAttempts++;
if ((maxTests && _testsRun >= maxTests) || !secondsBetweenTests) {
deferred.reject("Last connection test failed, " + _testsRun + " tests completed.");
} else {
deferred.notify(connectMessage);
deferred.notify("Connection will be retried in " + secondsBetweenTests + " seconds.");
var retryInterval = $interval(
function retryMessage(counter) {
deferred.notify(connectMessage);
var secondsLeft = (secondsBetweenTests - 1) - counter;
deferred.notify("Connection will be retried in " + secondsLeft + " second" + (secondsLeft > 1 ? "s." : "."));
if (!secondsLeft) {
$interval.cancel(retryInterval);
retryInterval = null;
}
},
1000, (secondsBetweenTests - 1));
}
}
return deferred.promise;
}
function _connectionTest() {
var deferred = $q.defer(),
getBroken = {
method: 'GET',
url: '/api/never/gonna/give/you/up'
};
$http(getBroken)
.success(function onSuccess() {
deferred.resolve('Success!');
})
.error(function onError() {
deferred.reject('Failure!');
});
return deferred.promise;
}
function _cancelConnectionTest() {
_testsRun = 0;
if (!_testConnectionInterval) {
$log.debug("No previously running connection test to cancel.");
return;
}
$log.debug("Cancelling connection test.");
$interval.cancel(_testConnectionInterval);
_testConnectionInterval = null;
}
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
<pre ng-controller="MainController">{{data.connectLog}}</pre>
</div>
答案 1 :(得分:6)
您可以在60秒内完成倒计时:
countdown(60);
function countdown(current_time){
if(current_time === 0){
//call function to connect to server
return;
}
else{
current_time--;
}
$scope.time = current_time;
$timeout(function(){countdown(current_time)}, 1000);
}
我建议将错误消息放在html中,然后用ng-show
或ng-if
隐藏它,然后只需更改号码,这样就不需要附加所有内容那个文字一遍又一遍。
答案 2 :(得分:4)
我不认为使用指令是必要的,你可以在控制器内做所有事情。无论您实施了closeConnection
还是openConnection
,都应该修改这些方法,然后添加&#39; start&#39;并且&#39;停止&#39; $interval
。
还要记住$interval
需要最多的递归次数,在这种情况下非常有用。
https://docs.angularjs.org/api/ng/service/ $间隔
function controllerFunc($scope, $interval) {
var timer;
var lastConnection = 0;
$scope.message = '';
//this is what you already have
$interval(function () {
us.isConnected().then(closeConnect, openConnect);
}, 60 * 1000);
//...
function closeConnect() {
//...
$interval.cancel(timer);
lastConnection = 0;
}
function openConnect() {
//...
timer = $interval(timerCall, 1000, 60);
lastConnection++;
}
function timerCall(times) {
$scope.message += 'Unable to establish a connection to the server for ' + lastConnection + ' minutes. ';
var retry = 60 - times;
$scope.message += 'Connection will be retried in '+ retry +' seconds';
}
}
格式化消息
$scope.message
在此示例中是一个纯字符串,因此您不会获得任何格式,但您可以将其放在ng-bind-html
指令中,然后将任何html标记添加到消息字符串中。
https://docs.angularjs.org/api/ng/directive/ngBindHtml
<div ng-bind-html="message"></div>
所以改变了js
$scope.message += '<p>Connection will be retried in '+ retry +' seconds</p>';
答案 3 :(得分:2)
我的指令非常相似,您可以查看here on plunker
基本上它使用(1)计时器&amp; (2)刷新状态,它也是可配置的,因为没有秒超时,从指令的attrs读取。
它在给定的间隔后调用给定的函数,它也会破坏$ scope更改的#interval。
以下是它的代码
app.directive("csAutoRefresh", ["$interval", function ($interval) {
var templateFn = function () {
var template = '<div class="text-left alert alert-success nopadding"';
template += 'style="margin-bottom: 0; margin-right: 0"> ';
template += ' <button class="btn btn-link" data-ng-click="factory.refresh.toggle()">';
template += '{{factory.refresh.refreshText()}}</button>';
template += '<span>...Refreshing upload status in ';
template += ' {{state.timer.timePending}} seconds</span>';
template += ' </div>';
return template;
};
var linkFn = function (scope) {
scope.pauseOn = scope.pauseOn === true;
scope.isprocessing = false;
scope.state = {
refresh : {
suspend : false
},
timer : {
timePending: 0,
refreshInterval : 60
}
}
function doRefresh() {
var refresh = {
pause: function () { scope.state.refresh.suspend = true; },
cont: function () { scope.state.refresh.suspend = false; },
toggle: function () { scope.state.refresh.suspend = !scope.state.refresh.suspend; },
refreshText: function () { return scope.state.refresh.suspend ? "Resume Refresh" : "Pause Refresh"; }
};
return refresh;
}
function doTimer() {
var timer = {
reset: function () { scope.state.timer.timePending = scope.state.timer.refreshInterval; },
update: function () {
if (scope.state.timer.timePending < 0) timer.reset();
scope.state.timer.timePending--;
},
done: function () { return scope.state.timer.timePending <= 0; },
force: function () { scope.state.timer.timePending = 0; }
};
return timer;
};
scope.factory = {
refresh: doRefresh(),
timer: doTimer()
};
if (angular.isDefined(scope.interval) && parseInt(scope.interval) > 0) {
scope.state.timer.refreshInterval = scope.interval;
}
scope.factory.timer.reset();
scope.$watch(function () {
return scope.state.timer.timePending;
}, function () {
if (!scope.factory.timer.done()) return;
var result = scope.$eval(scope.onTimeout);
if (angular.isObject(result) && angular.isFunction(result.then)) {
scope.isprocessing = false;
scope.factory.timer.reset();
result.finally(function () { scope.factory.timer.reset(); });
} else {
scope.isprocessing = false;
scope.factory.timer.reset();
}
});
scope.$watch('pauseOn', function () {
if (scope.pauseOn) {
scope.factory.refresh.pause();
} else {
scope.factory.timer.reset();
scope.factory.refresh.cont();
}
});
var updateTimer = function () {
if (scope.isprocessing) return;
if (scope.state.refresh.suspend) return;
scope.factory.timer.update();
};
var interval = $interval(updateTimer, 1000);
scope.$on('$destroy', function () {
$interval.cancel(interval);
});
};
return {
restrict: 'E',
scope: { onTimeout: '&', pauseOn: '=', interval: '@' },
template: templateFn,
link: linkFn,
};
}]);
答案 4 :(得分:1)
$interval(function () {
us.isConnected().then(closeConnect, openConnect);
}, 1000);
不
$interval(function () {
us.isConnected().then(closeConnect, openConnect);
}, 20 * 1000);
后者每隔20秒(20 * 1000ms)进行一次检查,所以除非实际的检查代码有问题,否则它应该每秒运行一次。
答案 5 :(得分:1)
因此,根据您希望如何向用户输出详细信息,您可能最好将其作为某种类型的指令并控制其中的所有内容。
执行您想要做的事情的关键是使用$ interval服务,该服务返回一个id:
$scope.intervalId = $interval(retryMessage, 1000);
然后您可以根据您的设置条件取消。
我做了一个plnkr来展示你想要实现的目标:
答案 6 :(得分:1)
我最近写了这个计时器,你可以从中得到一些逻辑 - Plunker。它计算向上,并且可以在设定的时间结束
JS
(function() {
'use strict';
var angularTimerApp = angular.module('angularTimerApp', []);
angularTimerApp.directive("angularTimer", function() {
return {
restrict: "E",
templateUrl: "angular-timer.html",
scope: {endTime: "@"},
controllerAs: "at",
bindToController: true,
controller: ["$scope", "$interval", function ($scope, $interval) {
var at = this;
at.secondsInAYear = 31536000;
at.secondsInADay = 86400;
at.secondsInAnHour = 3600;
at.secondsInAMinute = 60;
at.endTimeValue = null;
$scope.$watch("at.endTime", function(newValue) {
if (angular.isDefined(newValue)) {
at.endTimeValue = parseInt(newValue); // No test for int
}
});
at.getTimeDisplay = function(seconds) {
var hoursTxt = Math.floor(((seconds % at.secondsInAYear) % at.secondsInADay) / at.secondsInAnHour);
var minutesTxt = Math.floor((((seconds % at.secondsInAYear) % at.secondsInADay) % at.secondsInAnHour) / at.secondsInAMinute);
var secondsTxt = (((seconds % at.secondsInAYear) % at.secondsInADay) % at.secondsInAnHour) % at.secondsInAMinute;
return ("Hours: " + hoursTxt + ", Minutes: " + minutesTxt + ", Seconds: " + secondsTxt);
};
at.reset = function () {
at.timeOffset = 0;
at.timeDisplay = at.getTimeDisplay(0);
};
at.reset();
at.stop = function () {
$interval.cancel(at.timer);
at.timeOffset = at.time;
};
at.start = function() {
at.timeStart = (new Date()).getTime();
at.timer = $interval(function() {
at.time = Math.floor(((new Date()).getTime() - at.timeStart) / 1000) + at.timeOffset;
if ((at.endTimeSet) && (at.endTimeValue !== null)) {
if (at.time > at.endTimeValue) {
at.stop();
}
else {
at.timeDisplay = at.getTimeDisplay(at.time);
}
}
else {
at.timeDisplay = at.getTimeDisplay(at.time);
}
}, 1000);
};
}]
};
});
})();
标记
<body>
<angular-timer end-time="10"></angular-timer>
</body>
角timer.html
{{at.timeDisplay}}
<br><br>
<button ng-click="at.start()">Start</button>
<br><br>
<button ng-click="at.stop()">Stop</button>
<br><br>
<button ng-click="at.reset()">Reset</button>
<br><br>
<input type="checkbox" ng-model="at.endTimeSet"> End at 27 seconds
答案 7 :(得分:1)
我认为你真正想要的是一个返回承诺的服务,一个将通知发送回控制器的承诺。 Here's这种服务的一个例子:
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@1.4.0-rc.0" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
</head>
<body ng-app="myapp" ng-controller="main">
<h1>Task Retry Example</h1>
<p>Task condition: {{value}}</p>
<button ng-click="value = true">Set task condition to true</button>
<button ng-click="reset()">Reset Task</button>
<p>{{msg}}</p>
<script>
var app = angular.module('myapp', []);
app.controller('main', function($scope, task){
var myTask = function(){
return $scope.value;
}
function success(result){
$scope.msg = result;
}
function failure(reason){
$scope.msg = reason;
}
function notify(value){
$scope.msg = value.message;
}
$scope.reset = function(){
$scope.value = false;
$scope.msg = "Loading...";
task.go(myTask, {maxAttempts: 3, waitTime: 3})
.then(success, failure, notify);
}
$scope.reset();
});
app.service('task', function($q, $timeout){
var DEFAULT_OPTIONS = {
maxAttempts: 1,
waitTime: 10
};
var thisOptions = {};
function _countDownStep(secondsLeft, attemptsLeft, countDownProgress, taskAttemptProgress){
if(secondsLeft <= 0){
countDownProgress.resolve(true);
return;
}
var attempt = thisOptions.maxAttempts - attemptsLeft,
msg = "Attempt failed; retrying (" + attempt + " of " + thisOptions.maxAttempts + ") in " + secondsLeft + " seconds...";
taskAttemptProgress.notify({
"state": "WAITING",
"message": msg
})
$timeout(function(){
_countDownStep(secondsLeft-1, attemptsLeft, countDownProgress, taskAttemptProgress);
}, 1000);
}
function _countDown(secondsLeft, attemptsLeft, progress){
var deferred = $q.defer();
_countDownStep(secondsLeft, attemptsLeft, deferred, progress);
return deferred.promise;
}
function _attempt(task, attemptsLeft, progress){
if(!angular.isFunction(task)) {
progress.reject("Task is not a function.");
return;
}
if(attemptsLeft <= 0){
progress.reject("Max attempts reached.");
}
var result = task();
if(result){
progress.resolve("Successfully completed task.");
}else {
--attemptsLeft;
if(attemptsLeft <= 0){
progress.reject("Max attempts reached.");
}
_countDown(thisOptions.waitTime, attemptsLeft, progress).then(function(){
var attempt = thisOptions.maxAttempts - attemptsLeft,
msg = "Making another attempt (" + attempt + " of " + thisOptions.maxAttempts + ")...";
progress.notify({
"state": "TRYING",
"message": msg
})
_attempt(task, attemptsLeft, progress);
});
}
}
function _go(task, options){
var deferred = $q.defer();
thisOptions = options || DEFAULT_OPTIONS;
_attempt(task, thisOptions.maxAttempts, deferred);
return deferred.promise;
}
return {
go: _go
}
});
</script>