簡體   English   中英

如何在JavaScript中創建服務器端進度指示器?

[英]How to create Server-side Progress indicator in JavaScript?

我想在我的網站中創建一個部分,其中用戶有幾個簡單的update按鈕。

這些update按鈕中的每個按鈕都將轉到服務器,並且將在后台進行很長時間的處理。

服務器處理數據時,我希望用戶擁有某種進度指示器,例如進度欄或文本百分比。

如果重要的話,我正在使用jQuery作為我的JavaScript庫,並使用CodeIgniter(PHP)作為服務器端框架。

我在想的是使用PHP的flush()函數向jQuery報告進度狀態,但是我不確定jQuery的Ajax函數在完成輸出之前正在讀取輸出...

因此,任何建議/解釋都將是有益和有益的!

我將為您提供一個使用WebSync On-Demand的示例,但是無論您選擇哪種服務器,都可以使用相同的方法。

這就是你要做的。 首先,以某種方式啟動長期運行的操作; 您的用戶單擊按鈕開始此過程(我將假設執行Ajax調用,但是無論如何都可以),然后您向他們返回某種標識符,我們將其稱為“ myId”,為其賦予值“ 1。 是否通過調用某種流程等來執行此操作,則取決於您。

然后,在該調用的回調中,您將編寫如下內容:

var myId = 1; // this would be set somewhere else
client.initialize('api key');
client.connect();
client.subscribe({
  channel: '/tasks/' + myId,
  onReceive: function(args){
    // update the progress bar
    myProgressBar.update(args.data.progress);
  }
});

要做的是訂閱您的客戶端以接收有關任務更新的通知,因此剩下的就是推送更新,無論您實際運行該任務的任何過程,您都可以這樣做。 看起來像(在PHP中,使用SDK):

$publisher = new Publisher(
    "11111111-1111-1111-1111-111111111111", // your api key again
    "mydomain.com" // your domain
);

// publish data
$response = $publisher->publish(array(
    array(
        'channel' => '/tasks/' . $myId, //comes from somewhere
        'data' => (object) array(
            'progress' => '45' //45% complete
        )
    )
));

// success if empty (no error)
$success = empty($response); 

而已; 隨着更新的發生,它們將實時推送到您的客戶端。

很難做到這一點。 我們為系統確定的是一個“偽造的”進度條-它只是一遍又一遍地進行動畫處理(由於它是動畫gif,因此您可能會想到!)。

另一種選擇是提交到一個腳本,並在后台進行該處理(並將進度輸出到文件),同時向另一個腳本發出Ajax請求,該腳本的唯一責任是讀取該進度文件並返回整個過程的距離。是。 這行得通-感覺有點麻煩,但至少可以解決您的直接問題。

我對彗星之類的東西知之甚少,所以這完全基於我目前的理解。

遲到了3年,但這是我想出的解決方案。 獎勵:它適用於IE7 +

用途:

事件表:

create table updates(
    evt_id int unsigned not null auto_increment,
    user_id int unsigned not null,
    evt_type enum('start','update','finish') not null,
    evt_msg varchar(255) not null,
    primary key (evt_id)
)

HTML:

<?php
include 'libconfig.php';
session_write_close();
if(count($_POST)){
    $db=db_get_connection();
    $stm=new PDOStatementWrapper(db_prepare($db,'INSERT INTO bupdates VALUES (:event_id,:user_id,:type,:message)'));
    if($stm->run(array(
        ':event_id'=>0,
        ':user_id'=>App::user()->getId(),
        ':type'=>$_POST['type'],
        ':message'=>$_POST['message']
    )))echo 'Inserted';
    return;
}
?>
<!doctype html>
<html>
<head>
<title>tester</title>
<link rel=stylesheet href="s/jquery-ui-1.10.3.custom.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="js/eventsource.js"></script>
<script src="js/json2.js"></script>
<script>
var MixerStatusMonitor=(function(){
    var _src=null,
    _handler={
        onStart:function(e){
            MixerStatus.setMax(parseInt(e.data));
        },
        onUpdate:function(e){
            var data=JSON.parse(e.data);
            MixerStatus.setValue(parseInt(data.progress));
            MixerStatus.setStatus(data.message);
        },
        onFinish:function(e){
            //var data=JSON.parse(e.data);
            MixerStatus.hide();
            _src.close();
        }
    };
    return {
        init:function(){
            if(_src)_src.close();
            _src=new EventSource('/daemon/updates.php?type=b');
            _src.addEventListener('update',_handler.onUpdate,false);
            _src.addEventListener('start',_handler.onStart,false);
            _src.addEventListener('finish',_handler.onFinish,false);
            MixerStatus.show();
        }
    };
})();
var MixerStatus=(function(){
        var dialog=null,pbar=null,text=null;
        return {
            init:function(){
                dialog=$('#buildStatus').dialog({autoOpen:false});
                pbar=$('#buildStatus .progress').progressbar({value:false});
                text=$('#buildStatus .text').progressbar();
            },
            setStatus:function(txt){
                text.html(txt);
            },
            setMax:function(val){
                pbar.progressbar('option','max',val);
            },
            setValue:function(val){
                pbar.progressbar('option','value',val);
            },
            show:function(){
                dialog.dialog('open');
            },
            hide:function(){
                dialog.dialog('close');
            }
        };
})();
$(document).ready(function(){
    MixerStatus.init();//build the UI
    $('#updater').on('submit',function(){
        $.ajax({
            type:'post',
            url:'test-updates.php',
            data:$('#updater').serialize(),
            beforeSend:function(){
                if($('#updater select[name=type]').val()=='start'){
                    MixerStatusMonitor.init();
                }
            }
        });
        return false;
    });
});
</script>
</head>
<body>
<p>Start event sets the max
<p>update event: {"progress":"","message":""}
<p>finish event: {"progress":"","message":""}
<form id=updater>
message: <input type=text name=message value="15"><br>
event type: <select name=type>
<option value=start>start</option>
<option value=update>update</option>
<option value=finish>finish</option>
</select><br>
<button>send message</button>
</form>
<div id=buildStatus title="Building">
<div class=text></div>
<div class=progress></div>
</div>
<div id=messages></div>
</body>
</html>

PHP:

<?php
header('Content-Type: text/event-stream');
define('TYPE_BROADCAST','b');
define('MAX_FAILURES',30);//30 seconds
define('MAX_WAIT',30);//30 seconds
define('MAX_START_WAIT',6);//30 seconds
/*
 * URL arguments:
 * type
 */
include '../libconfig.php';
session_write_close();
if(!App::loggedIn() || !App::user()){
    printEvent(0,'finish','Login session has expired.');
}
if($_GET['type']==TYPE_BROADCAST){//not needed;specific to the app I am creating
    $db=db_get_connection();
    $stm=new PDOStatementWrapper(db_prepare($db,'SELECT * FROM updates WHERE user_id=:user_id AND evt_id>:last_id'));
    $args=array(':user_id'=>App::user()->getId(),':last_id'=>0);
    $stm->bindParam(':user_id',$args[':user_id'],PDO::PARAM_INT);
    $stm->bindParam(':last_id',$args[':last_id'],PDO::PARAM_INT);
    $failures=0;
    $nomsg=0;
    if(!isset($_SERVER['HTTP_LAST_EVENT_ID'])){
        $start=new PDOStatementWrapper(db_prepare($db,'SELECT * FROM updates WHERE user_id=:user_id ORDER BY evt_id DESC'));
        $start->bindValue(':user_id',$args[':user_id'],PDO::PARAM_INT);
        $startwait=0;
        while(1){
            if($startwait>MAX_START_WAIT){
                printEvent(0,'finish','Timed out waiting for the process to start.');
                return;
            }
            sleep(5);
            $startwait++;
            if(!$start->run()){
                printEvent(0,'finish','DB error while getting the starting event.');
                return;
            }
            while($start->loadNext()){
                if($start->get('evt_type')=='finish')continue 2;
                if($start->get('evt_type')=='start')break;
            }
            if($start->get('evt_type')=='start'){
                $args[':last_id']=$start->get('evt_id');
                printEvent($start->get('evt_id'),'start',$start->get('evt_msg'));
                break;
            }
        }
    }else
        $args[':last_id']=$_SERVER['HTTP_LAST_EVENT_ID'];
    if($args[':last_id']===0){
        printEvent(0,'finish','ll');
        exit;
    }
    while(1){
        sleep(1);
        if(!$stm->run()){
            $failures++;
            if($failures>MAX_FAILURES){
                printEvent(0,'finish','Max failures reached.');
                break;
            }
        }
        if($stm->loadNext()){
            $failures=0;
            $nomsg=0;
            do{
                if($stm->get('evt_type')=='finish')break;
                $args[':last_id']=$stm->get('evt_id');
                printEvent($stm->get('evt_id'),$stm->get('evt_type'),$stm->get('evt_msg'));
            }while($stm->loadNext());
            if($stm->get('evt_type')=='finish'){
                printEvent($args[':last_id'],'finish',$stm->get('evt_msg'));
                break;
            }
        }else{
            $nomsg++;
            if($nomsg>MAX_WAIT){
                exit;//TODO: test
            }
        }
    }
}else{
    printEvent(0,'close','Unknown event type.');
}

function printEvent($id,$name,$data){
    echo "id: $id\nevent: $name\n";
    if(is_array($data)){
        foreach($data as $datum)
            echo "data: $datum\n";
        echo "\n";
    }else
        echo "data: $data\n\n";
    flush();
    if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
        $_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest')exit;//ajax request. Need to kill the connection.
}

如果您想知道PDOStatementWrapper的源在這里 抱歉,它不包含與CodeIgniter集成的任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM