我有下面的Angular网站,它显示Angular可以更新页面,而PHP可以在后台通过AJAX执行一些过程。
然而,我现在如何获得我的PHP进程,例如for
循环,以传递回$x
的值,这样我就可以在$x
递增时显示它的后面?
index.php
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ajaxtest</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
</head>
<body ng-app="mainApp">
<div ng-controller="mainController">
<div>Angular is counting: {{counter}}</div>
<button ng-click="processFiles()">processFiles</button>
<div>{{message}}</div>
</div>
<script>
var mainApp = angular.module('mainApp',[]);
function mainController($scope, $interval, $http) {
var theTimer = $interval(function () {
$scope.counter++;
}, 1000);
$scope.counter = 0;
$scope.message = 'click the button to have PHP do something in the background while Angular should continue to count';
$scope.processFiles = function() {
$scope.message = 'processing...';
$http.get('http://localhost/webs/ajaxtest/data.php', {
params: {
taskIdCode: 'getLoadingStatus'
}
}).success(function (data) {
$scope.message = data['status'];
});
}
}
</script>
</body>
</html>
data.php
$taskIdCode = filter_input(INPUT_GET, 'taskIdCode', FILTER_UNSAFE_RAW);
$methodName = 'task_' . $taskIdCode;
$this->$methodName();
}
public function task_getLoadingStatus() {
for($x = 1; $x <= 4; $x++) {
sleep(1);
}
$data['status'] = 'finished';
echo json_encode($data);
}
}
$taskRunner = new TaskRunner();
正如Ricardo所说,一种选择是通过调用处理的同一通道反馈状态消息-这在AJAX请求上在技术上是可行的,但需要对Web服务器和任何中间组件进行大量修改,以将内容刷新回Javascript,并需要对Javascript进行复杂处理以处理部分响应。这就是websocket要解决的问题。通过HTTP请求处理长时间运行的进程不是一种好的做法。
对这种方法的进一步考虑是,HTTP及其基础设施是围绕服务器对请求做出快速响应的概念设计的。
如果你不走这条路,那么你需要通过另一个渠道提供数据——显而易见的解决方案是AJAX Web服务,它会及时响应当前状态。
但由于这与调用无关,因此它需要一种机制来引用正在监视的特定进程。如果你已经有了一个会话,那么你可以使用会话id或会话本身作为密钥——然而,如果会话与多个这样的进程相关联,这是行不通的。此外,通过javascript公开会话id对安全性有很大影响。
或者,您可以用javascript创建一个(希望是唯一的)密钥,并将该密钥注入到流程调用中。
var taskKeyValue=generate_unique_id();
var keepChecking;
// first invoke processing.....
$scope.processFiles = function() {
$scope.message = 'processing...';
$http.get('http://localhost/webs/ajaxtest/data.php', {
params: {
taskKey: taskKeyValue
}
}).success(function (data) {
$scope.message = data['status'];
clearInterval(keepChecking);
});
// then while this is outstanding
var checkFiles = function() {
$http.get('http://localhost/webs/ajaxtest/pollStatus.php', {
params: {
taskKey: taskKeyValue
}
}).success(function (data) {
$scope.message = data['status'];
});
keepChecking=set_interval(checkFiles, 2000);
然后在您现有的php代码中。。。。
function doing_slow_thing() {
for($x = 1; $x <= 40; $x++) {
file_put_contents('/tmp/' . basename($_GET['taskKey']), $x);
sleep(1);
}
$data['status'] = 'finished';
echo json_encode($data);
}
和pollStatus.pp:
<?php
print json_encode(
array('status'
=>file_get_contents('/tmp/' . basename($_GET['taskKey']))
));
如果您不使用Websockets(或某种类型的服务器推送),您将不得不采用长轮询。
我的建议是在你的控制器中如下:
var promise = null;
var poller = function() {
console.log("Query the server for the amount of progress done using another $http.get");
};
在执行$http.get
以启动长操作之前的功能中:
$scope.processFiles = function() {
$scope.message = 'processing...';
//
// Initialize the interval pooling operation
//
var promise = $interval(poller, 1000);
$http.get('http://localhost/webs/ajaxtest/data.php', {
params: {
taskIdCode: 'getLoadingStatus'
}
}).success(function (data) {
//
// Terminate the interval so it does not run forever!
//
$interval.cancel(promise);
$scope.message = data['status'];
}).error(function() {
$interval.cancel(promise);
});
}
然后,在服务器端,您必须将进度存储在数据库中(或您可能拥有的任何等效内容),以便由轮询操作进行检查。在sleep
之后,每个进度步骤都必须更新此状态。
希望这些信息能让你开始:)