Yii2 HTML5 Server-Sent事件在服务器上不是实时的

时间:2016-11-18 11:05:53

标签: php jquery html5 yii2 server-sent-events

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

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();
    }

}

1 个答案:

答案 0 :(得分: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