【问题标题】:Update live data (like progress bar) in view with Laravel 4使用 Laravel 4 更新实时数据(如进度条)
【发布时间】:2013-08-23 01:15:57
【问题描述】:

TL;DR

我想发送数据以在视图中实时更新,例如进度 显示操作状态的栏。 在 laravel 4 中最好的方法是什么?


设置

我正在开发一个基于 Laravel 4 的项目,每个用户都可以兑换一个序列号。

我创建了一个管理后台,可以轻松粘贴到密钥列表中,或上传密钥文件。

假设$key_string 是我上传的以换行符分隔的键的字符串,并且想要解析出来然后上传包含的键字符串 - 这是添加键的简化代码:

$key_string = rtrim($key_string);
$key_string = str_replace("\n\r", "\n", $key_string);
$keys = explode( "\n", $key_string);

foreach($keys as $index => $key) {
    Key::create(
        array( "serial" => trim($key) )
    );
}

由于我上传的密钥集数以千计,这有时可能需要 30 秒,在此期间管理面板自然不会显示任何内容。

现在,我不介意花点时间。我不需要优化上传以使用一个查询等,但我想得到一些实际的反馈,以便我知道上传已经走了多远。


问题

当我上传密钥时,我希望能够每隔几秒或百分比刻度更新我视图中的进度条或计数器(使用当前的$index

有没有一种简单的方法可以轻松地处理这个问题,最好集成在 Laravel 4 中?我假设这将涉及 ajax,但有人能指出我正确的方向吗?

【问题讨论】:

    标签: php ajax laravel laravel-4


    【解决方案1】:

    无论您使用 Laravel 还是 Core PHP 编写代码,都应该尝试一下 Server sent events。使用 SSE 很容易做到。

    基本上包括两部分:-

    1. Javascript API(客户端) - 您必须订阅一个事件流,创建一个 EventSource 对象并将您的流的 URL 传递给它,如下所示:-

    if (!!window.EventSource) {
      var source = new EventSource('stream.php');
    } else {
      // Result to xhr polling :(
    }
    

    然后为消息事件设置一个处理程序。您可以选择监听打开和错误:-

    source.addEventListener('message', function(e) {
      console.log(e.data);
    }, false);
    
    source.addEventListener('open', function(e) {
      // Connection was opened.
    }, false);
    
    source.addEventListener('error', function(e) {
      if (e.readyState == EventSource.CLOSED) {
        // Connection was closed.
      }
    }, false);
    

    2。 PHP(服务器端) - 您必须发送 Content-Type: text/event-stream 标头,然后在处理时以预定义格式推送响应,如下所示:-

    <?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
    
    /**
     * Constructs the SSE data format and flushes that data to the client.
     *
     * @param string $id Timestamp/id of this connection.
     * @param string $msg Line of text that should be transmitted.
     */
    function sendMsg($id, $msg) {
      echo "id: $id" . PHP_EOL;
      echo "data: $msg" . PHP_EOL;
      echo PHP_EOL;
      ob_flush();
      flush();
    }
    
    $serverTime = time();
    
    sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));
    

    所有sn-ps都是从上述链接中借用的,建议进行彻底的研究以获得清晰的理解。

    干杯

    【讨论】:

      【解决方案2】:

      使用 PHP 确实有两种选择,无需使用 Web Sockets 或 Push-Pull 设置。这并不是真正的 Laravel 东西,它更像是一个请求 JSON“东西”的 AJAX 循环。

      短轮询

      Olark 将这种方法用于他们的聊天脚本。

      setInterval(function() {
          $.getJSON("/path", function(data) {
              // update the view with your fresh data
          });
      }, 5000);
      

      长轮询

      Javascript

      var eventName = function() {
          $.getJSON("/path", function(data) {
              // update the view with your fresh data
              if (data.progress < 100)
                  eventName();
          });
      };
      

      控制器逻辑

      当我让用户上传 CSV 并等待它完成上传并被处理时,我会使用它。

      // in your controller
      $check = true;
      while ($check) {
          // search database
          // compare values
          if ($newDataWasFound)
              $check = false;
      
          $progressFromAbove = 90;
      }
      
      return Response::json(array(
          'newData' => $array,
          'progress' => $progressFromAbove,
      ));
      

      我使用 Laravel 3 对此进行了截屏,但长轮询与 PHP 无关,与 Laravel 无关。 https://www.youtube.com/watch?v=LDgJF77jELo

      示例

      【讨论】:

      • 有趣。您是否会建议任何资源可以清楚地概述短极化和长极化之间的区别以及何时使用其中任何一个?我更喜欢从头开始一个简单项目的东西。
      • @Johannes 不幸的是,根据我的经验并非如此。对于 PHP,互联网上散布着这些破烂的例子。我会在我的回答中得到更多的例子。
      【解决方案3】:

      你可以把它放在 Session 中,然后从另一个链接获取它。

      $key_string = rtrim($key_string);
      $key_string = str_replace("\n\r", "\n", $key_string);
      $keys = explode( "\n", $key_string);
      
      $count = 0;
      foreach($keys as $key) {
        Key::create(
            array( "serial" => trim($key) )
        );
        $count++;
        if($count % 5== 0) Session::put('count',$count);
      }
      
      
      //route.php
      Route::get('/count', function()
      {
         if( Session::has('count'))
              return Session::get('count');
      });
      

      【讨论】:

      • 你可以通过 ajax 调用 "/count"。
      • 嗯,所以我会每隔 X 秒调用一次 ajax 代码?还是只有在数据实际更新后才能做到这一点?
      • 没办法。您应该每 X 秒调用一次。因为网络是无状态的。这意味着服务器无法在没有客户端请求的情况下发送数据。 WebSocket 作为 HTML5 的一部分将提供它,但它还没有完全支持。
      • 好吧,我想一个简单的处理方法是让服务器存储上次更新数据的时间,然后你有 ajax 查询,只有当你看到有一个更新,你会查询其他的东西。感谢您提供有用的答案和代码。 +1
      • stackoverflow.com/questions/12373373/jqueryui-progress-bar 可能会有所帮助。您必须进行一些数学运算才能根据计数和总数计算出要填写多少条。一旦达到 100,使用 clearInterval() 将其停止。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-16
      • 2021-07-09
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多