如何让PHP更新冗长进程状态的javascript?

时间:2015-10-29 11:33:19

标签: javascript php angularjs

我有以下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();

2 个答案:

答案 0 :(得分:3)

正如里卡多所说,一种选择是通过调用处理的同一频道反馈状态消息 - 这在技术上可能超过AJAX请求,但需要对网络服务器和任何中间组件进行大量修改。将内容刷新回Javascript,以及javascript中的复杂性来处理部分响应。这是websockets旨在解决的问题。通过HTTP请求处理long running process是不好的做法。

对此方法的进一步考虑是HTTP及其基础结构是围绕服务器及时响应请求的概念而设计的。

如果你没有沿着这条路走下去,那么你需要通过一个不同的渠道提供数据 - 显而易见的解决方案是一个AJAX网络服务,它将迅速响应当前状态。

但由于它与调用分离,因此需要一种机制来引用正在监视的特定进程。如果您已经有会话,那么您可以使用会话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.php:

<?php
    print json_encode(
          array('status'
             =>file_get_contents('/tmp/' . basename($_GET['taskKey']))
          ));

答案 1 :(得分:0)

如果您不使用Websockets(或某种类型的服务器推送),您将不得不诉诸long-polling

我的建议是你的控制器中的以下内容:

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之后的每个进度步骤,您都必须更新此状态。

希望这些信息可以帮助您入门:)