JavaScript Sunucu tarafı İlerleme göstergesi oluşturmak nasıl?

3 Cevap php

Ben bir kullanıcı bir kaç basit update düğmeleri vardır sitemde bir bölüm oluşturmak istiyorum.

Bunların her biri update düğmeleri sunucu olacak ve sahne arkasında uzun bir çatırdayan yapacağız.

Sunucu veri egzersizi yaparken, ben ilerleme çubuğu veya metinsel yüzdesi gibi, kullanıcı ilerleme göstergesinin bir çeşit sahip olmak istiyorum.

Bu çok önemli eğer, sunucu tarafı çerçeve olarak benim JavaScript kütüphanesi olarak jQuery kullanarak, ve CodeIgniter (PHP) ediyorum ...

JQuery ilerleme durumunu bildirmek için PHP'nin flush() işlevini kullanarak düşünüyordum, ama tam olmadan jQuery Ajax fonksiyonları çıktısını okuyarak emin değilim Ne ...

Yani herhangi bir tavsiye / açıklama faydalı ve yararlı olacaktır!

3 Cevap

I WebSync On-Demand kullanarak size bir örnek vereceğim, ama aynı yaklaşım ne olursa olsun sunucu seçtiğiniz çalışacak.

İşte yapmanız gerekenler var. İlk olarak, bir şekilde uzun süreli işlem başlaması; Kullanıcı (ben bir Ajax çağrısı kabul edeceğim, ama ne olursa olsun çalışır ediyorum), ve onlara tanımlayıcı çeşit dönmek bu süreci başlatmak için düğmeye tıkladığında, biz 'MyID', o 'bir değer vermesidir ararım 1 '. Vb, bazı tür bir süreç çağırarak, size kalmış olduğunu yapmak ister.

Sonra, o çağırma geri arama, bunu gibi bir şey yazmak istiyorum:

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

Ne yapacağım görev güncellemeleri hakkında bildirim almak için müşteri abone olduğunu, bu yüzden tüm bu kalan aslında görevi çalışan ne olursa olsun işlem yapmak istiyorum, hangi güncellemeleri dışarı itmek değildir. Yani (SDK kullanarak, PHP) gibi görünecektir:

$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); 

İşte bu; güncelleştirmelerin ortaya gibi, gerçek-zamanlı olarak müşteri için dışarı itmek gerekir.

Bu hakkı elde etmek oldukça zor. Ne bizim sistem yerleşmiş ettik "sahte" ilerleme çubuğu - sadece (bir animasyonlu gif olduğundan, size beklediğinizden hangi!) Ve üzerinde canlandırır.

Olan sadece sorumluluk olduğunu ilerleme dosyasını okuyun ve sürecinde ne kadar dönmek için başka bir komut için bir Ajax isteği yaparken alternatif 1 komut göndermek için olacak, ve arka planda bu işleme var (ve bir dosyaya ilerleme çıktısı) olur sen bulunmaktadır. Bu çalışacak - bu biraz kıytırık hissediyor, ama en azından acil sorunu çözmek olacaktır.

Ben Comet veya seviyor hakkında çok az şey biliyoruz, yani bu tamamen benim şimdiki anlayışa dayanmaktadır.

3 yıl geç, ama burada ben ile geldi bir çözüm. Bonus: Bu IE7 + çalışır

Kullanım Alanları:

Olay tablosu:

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.
}

Eğer o here olduğu için PDOStatementWrapper Kaynak merak ediyorduk. Maalesef bu CodeIgniter ile entegre bir şey içermez.