2016-11-18 75 views
0

我有一个长时间运行的任务(for循环每次迭代1秒睡眠),我想在每次迭代更新进度条,我使用HTML5服务器发送的事件,但请求状态等待10秒,在更新完成进度条之后,这意味着它不是实时的,我应该说我在许多PC,笔记本电脑,手机......上用各种操作系统和网络浏览器检查了我的代码。它正在处理所有这些问题,就在我的笔记本电脑上,Windows 7 Home Premium无法正常工作!当它在localhost上工作时,我也在互联网上发现了一个SSE的演示(SSE Demo),它也在我的笔记本上工作。我很困惑!!,任何想法? 谢谢先进。Yii2 HTML5服务器发送的事件不是服务器上的实时

Start Task

End of task

视图文件(sse.php):

<?php 

use yii\helpers\Html; 

$this->title = Yii::t('app', 'Server-Sent Event'); 
$this->params['breadcrumbs'][] = $this->title; 

$js = ' 

var es; 

function startTask() { 
    es = new EventSource("'.Yii::$app->urlManager->createUrl('province/default/sse').'"); 

    //a message is received 
    es.addEventListener("message", function(e) { 
     var result = JSON.parse(e.data); 

     addLog(result.message);  

     if(e.lastEventId == "CLOSE") { 
      addLog("Received CLOSE closing"); 
      es.close(); 
      var pBar = document.getElementById("progressor"); 
      pBar.value = pBar.max; //max out the progress bar 
     } 
     else { 
      var pBar = document.getElementById("progressor"); 
      pBar.value = result.progress; 
      var perc = document.getElementById("percentage"); 
      perc.innerHTML = result.progress + "%"; 
      perc.style.width = (Math.floor(pBar.clientWidth * (result.progress/100)) + 15) + "px"; 
     } 
    }); 

    es.addEventListener("error", function(e) { 
     addLog("Error occurred"); 
     es.close(); 
    }); 
} 

function stopTask() { 
    es.close(); 
    addLog("Interrupted"); 
} 

function addLog(message) { 
    var r = document.getElementById("results"); 
    r.innerHTML += message + "<br>"; 
    r.scrollTop = r.scrollHeight; 
} 

$(document).on("click", "#start_task", function() { 
    startTask(); 
}); 

$(document).on("click", "#stop_task", function() { 
    stopTask(); 
}); 

'; 
$this->registerJs($js); 
?> 

<div class="clearfix"></div> 
<div class="box box-solid box-primary"> 
    <div class="box-header"> 
     <h3 class="box-title"><?= Html::encode($this->title) ?></h3> 
    </div> 
    <div class="box-body"> 

        <br /> 
        <input type="button" id="start_task" value="Start Long Task" /> 
        <input type="button" id="stop_task" value="Stop Task" /> 
        <br /> 
        <br /> 
           
        <p>Results</p> 
        <br /> 
        <div id="results" style="border:1px solid #000; padding:10px; width:300px; height:250px; overflow:auto; background:#eee;"></div> 
        <br /> 
           
        <progress id='progressor' value="0" max='100' style=""></progress>  
        <span id="percentage" style="text-align:right; display:block; margin-top:5px;">0</span> 

    </div> 
</div> 

控制文件(DefaultController):

<?php 

namespace frontend\modules\province\controllers; 

use Yii; 
use yii\filters\AccessControl; 
use yii\web\Controller; 
use yii\web\BadRequestHttpException; 

/** 
* Default controller for the `province` module 
*/ 
class DefaultController extends Controller 
{ 
    public function actionTestSse() 
    { 
     return $this->render('sse');  
    } 

    public function actionSse() 
    { 
     header('Content-Type: text/event-stream'); 
     header('Cache-Control: no-cache'); 

     for($i = 1; $i <= 10; $i++) { 
      $this->send_message($i, 'on iteration ' . $i . ' of 10' , $i*10); 
      sleep(1); 
     } 
     $this->send_message('CLOSE', 'Process complete', 100); 
    } 

    public function send_message($id, $message, $progress) { 
     $d = array('message' => $message , 'progress' => $progress); 

     echo "id: $id" . "\n\n"; 
     echo "data: " . json_encode($d) . "\n\n"; 
     echo "\n\n"; 

     ob_flush(); 
     flush(); 
    } 

} 
+0

您的请求没有完成,直到你的行动结束时,也就是当服务器实际上发回了整个10个周期的响应。您为服务器发送的事件配置的操作是检查状态的操作,而不是执行实际工作的操作。 – marche

+0

marche它在localhost上工作,但不在服务器上,今天我用chrome在android上检查它,它工作正常!不能用Chrome或Firefox在windows上工作! – SADi

+0

我看不出它会如何处理你的代码。每一个使用send_message的函数都会返回给用户,这就是为什么你在请求的整个10秒内得到挂起状态的原因。您回复的所有内容都会作为HTML5 Server-Sent Event所做的单个请求的响应发回给用户。 – marche

回答

0

好了,所以在这里做了一些测试后就是一个例子。

首先控制器:

<?php 

namespace app\controllers; 

use Yii; 
use yii\web\Controller; 
use app\models\Task; 

class SiteController extends Controller 
{ 
    public function actionTask() { 
     return $this->render('task'); 
    } 

    public function actionDoTask() { 
     $task = Task::find()->one(); 
     if($task === null) { 
      $task = new Task(); 
     } 
     $task->totalIterations = 10; 
     $task->started = date('Y-m-d H:i:s'); 
     $task->iteration = 0; 
     $task->percentage = 0; 
     $task->save(); 

     for($i = 1; $i <= 10; $i++) { 
      sleep(1); 
      $task->iteration = $i; 
      $task->percentage = ($i * 100)/$task->totalIterations; 
      $task->save(); 
     } 
     return 'Some Result'; 
    } 

    public function actionCheckTaskProgress() { 
     header('Content-Type: text/event-stream'); 
     header('Cache-Control: no-cache'); 

     $task = Task::find()->one(); 
     if($task !== null) { 
      $data = ['message' => "on iteration " . $task->iteration . " of " . $task->totalIterations, 'progress' => $task->percentage]; 
     } 
     else { 
      $data = ['message' => "on iteration 0 of ?", 'progress' => 0]; 
     } 

     echo "data: " . json_encode($data) . "\n\n"; 

     ob_flush(); 
     flush(); 
    } 
} 

查看:

<?php 

/* @var $this yii\web\View */ 

use yii\helpers\Html; 

$this->title = 'HTML5 Server-Sent Events'; 
$this->params['breadcrumbs'][] = $this->title; 

$js = ' 

var es; 

var xmlHttp; 

function startTask() { 
    // Do an async request for some result 
    xmlHttp = new XMLHttpRequest(); 
    xmlHttp.onreadystatechange = function() { 
     if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { 
      es.close(); 
      addLog(xmlHttp.responseText); 
      var pBar = document.getElementById("progressor"); 
      pBar.value = 100; 
      var perc = document.getElementById("percentage"); 
      perc.innerHTML = "100%"; 
      perc.style.width = (Math.floor(pBar.clientWidth) + 15) + "px"; 
     } 
    } 
    xmlHttp.open("GET", "'.Yii::$app->urlManager->createUrl('site/do-task').'", true); 
    xmlHttp.send(null); 

    setTimeout(function(){ 
     es = new EventSource("'.Yii::$app->urlManager->createUrl('site/check-task-progress').'"); 

     es.addEventListener("message", function(e) { 
      var result = JSON.parse(e.data); 
      if(result.progress == 100) { 
       es.close(); 
      } 
      addLog(result.message); 

      var pBar = document.getElementById("progressor"); 
      pBar.value = result.progress; 
      var perc = document.getElementById("percentage"); 
      perc.innerHTML = result.progress + "%"; 
      perc.style.width = (Math.floor(pBar.clientWidth * (result.progress/100)) + 15) + "px"; 
     }); 
    }, 100); 
} 

function addLog(message) { 
    var r = document.getElementById("results"); 
    r.innerHTML += message + "<br>"; 
    r.scrollTop = r.scrollHeight; 
} 

$(document).on("click", "#start_task", function() { 
    startTask(); 
}); 

'; 

$this->registerJs($js); 
?> 

<div class="clearfix"></div> 
<div class="box box-solid box-primary"> 
    <div class="box-header"> 
     <h3 class="box-title"><?= Html::encode($this->title) ?></h3> 
    </div> 
    <div class="box-body"> 

     <br /> 
     <input type="button" id="start_task" value="Start Long Task" /> 
     <br /> 
     <br /> 

     <p>Results</p> 
     <br /> 
     <div id="results" style="border:1px solid #000; padding:10px; width:300px; height:250px; overflow:auto; background:#eee;"></div> 
     <br /> 

     <progress id='progressor' value="0" max='100' style=""></progress> 
     <span id="percentage" style="text-align:right; display:block; margin-top:5px;">0</span> 

    </div> 
</div> 

我的结果:

HTML5 Server-Sent Events Demo Results

+0

感谢你的例子,但我检查了我的许多PC,笔记本电脑,手机,...与各种操作系统和Web浏览器的代码。它正在处理所有这些问题,就在我的笔记本电脑上,Windows 7 Home Premium无法正常工作! – SADi