Mar*_*ama 7 javascript php loops loading polling
我想在PHP中创建类似于加载器的东西,所以我使用了这段代码:
<?php
$x=1;
while($x<=100) {
echo "Loading: $x %<br>";
$x++;
}
?>
Run Code Online (Sandbox Code Playgroud)
这样它将显示从"加载1%"到"加载100%".但是,这将导致所有出现的一个在新线出现后不会消失.因此,我想知道如何使新行显示并且旧的消失,并且这在页面加载后开始,因此用户将能够观看实际加载的加载器从1%到100%.
更新:我知道我应该使用JS和/或Ajax来实现它,我只是想知道是否有办法在PHP中也这样做:)
Anr*_*nri 38
PHP是一种服务器端语言,它根据请求为您提供响应.
你无法在DOM上操纵(就像你想要的那样).
为此你应该使用javascript和AJAX来改变基于PHP结果的DOM元素
Ala*_*blo 28
遵循长时间运行的任务很常见,但第一次实施起来并不容易.这是一个完整的例子.
(Sellermania产品中长期运行任务的样本)
想象一下,您目前有以下任务,并希望向访问者显示进度条.
PHP task.php
<?php
$total_stuffs = 200;
$current_stuff = 0;
while ($current_stuff < $total_stuffs) {
$progress = round($current_stuff * 100 / $total_stuffs, 2);
// ... some stuff
sleep(1);
$current_stuff++;
}
Run Code Online (Sandbox Code Playgroud)
你漂亮的UI看起来像这样:

HTML ui.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>My Task!</title>
</head>
<body>
<a id="run_task" href="#">Run task</a>
<div id="task_progress">Progression: <span id="task_progress_pct">XX</span>%
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
$('#run_task').click(function(e) {
e.preventDefault();
$.get('task-launch.php');
});
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
我们需要在后台启动任务,以使此演示相关.因此,当单击"运行"时,将异步调用此PHP脚本,并将在后台执行上述任务.
PHP 任务-launch.php
<?php
// launches the task in background
// see https://stackoverflow.com/a/12341511/731138 for details about the arguments
exec("/usr/bin/php task.php > /dev/null 2>&1 &");
Run Code Online (Sandbox Code Playgroud)

这里有3个问题:
你可以通过点击几次运行按钮多次运行任务,如何在后台同时避免多个任务?
任务在服务器端运行,因此我们需要做一些事情来访问服务器并询问进度信息.
当我们将连接到服务器端时,该$progress变量不可用于读取,因为它存储在task.php正在运行的实例的上下文中.

通常,进度信息存储在数据库或文件中,或者程序可以写入的任何内容中(您的任务可行),并且可以被其他人(您应该显示进展的ui)读取.
我开发了一个用于在几个php应用程序中共享数据的类(在github上可用),它的工作方式与stdClass将其内容安全地同步到文件中的方式相同.
只需下载src/Sync.php并更改上面的task.php:
PHP task.php
<?php
require("Sync.php");
$total_stuffs = 200;
$current_stuff = 0;
$shared = new Sync("some_file.txt");
$shared->progress = 0;
while ($current_stuff < $total_stuffs) {
$shared->progress = round($current_stuff * 100 / $total_stuffs, 2);
// ... some stuff
sleep(1);
$current_stuff++;
}
// to tell the follower that the task ended
$shared->progress = null;
Run Code Online (Sandbox Code Playgroud)
重要说明:此处some_file.txt是存储任务共享数据的位置,因此如果每个用户都有自己的任务,请不要犹豫使用"task_ [user_id] .txt".并查看github上的自述文件以优化文件访问.
PHP 任务-launch.php
<?php
require("Sync.php");
$shared = new Sync("some_file.txt");
if (is_null($shared->progress)) {
exec("/usr/bin/php task.php > /dev/null 2>&1 &");
}
Run Code Online (Sandbox Code Playgroud)
PHP task.php
<?php
require("Sync.php");
$total_stuffs = 200;
$current_stuff = 0;
$shared = new Sync("some_file.txt");
// here is the magic: impossible to set the progression to 0 if an instance is running
// ------------------
$shared->lock();
if (!is_null($shared->progress))
{
$shared->unlock();
exit ;
}
$shared->progress = 0;
$shared->unlock();
// ------------------
while ($current_stuff < $total_stuffs) {
$shared->progress = round($current_stuff * 100 / $total_stuffs, 2);
// ... some stuff
sleep(1);
$current_stuff++;
}
// the task ended, no more progression
$shared->progress = null;
Run Code Online (Sandbox Code Playgroud)
警告:如果您的任务崩溃并且永远不会到达终点,您将永远无法再启动它.为了避免这种情况,您还可以将子项getmypid()和一些内容存储在time()共享变量中,并在任务中添加超时逻辑.
轮询代表每过一段时间(例如,1秒,5秒或其他)向服务器询问进展信息.总之,客户端每隔N秒向服务器询问进度信息.
PHP 任务follow.php
<?php
require("Sync.php");
$shared = new Sync("some_file.txt");
if ($shared->progress !== null) {
echo $shared->progress;
} else {
echo "--"; // invalid value that will break polling
}
Run Code Online (Sandbox Code Playgroud)
HTML UI的polling.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>My Task!</title>
</head>
<body>
<a id="run_task" href="#">Run task</a>
<div id="task_progress">Progression: <span id="task_progress_pct">XX</span>%
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
$('#run_task').click(function(e) {
e.preventDefault();
<!-- not a good practice to run a long-running task this way but that's a sample -->
$.get('task-launch.php');
<!-- launches the polling business -->
setTimeout(function() {
getProgressionInformation();
}, 1000);
});
function getProgressionInformation() {
$.get('task-follow.php', function(progress) {
$('#task_progress_pct').html(progress);
if (progress !== '--') {
<!-- if the task has not finished, we restart the request after a 1000ms delay -->
setTimeout(function() {
getProgressionInformation();
}, 1000);
}
});
}
/* the task might be already running when the page loads */
$(document).ready(function() {
getProgressionInformation();
});
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

我还开发了一个jquery插件,domajax,打算做"没有javascript的ajax"(实际上,插件本身是在jQuery中,但使用它不需要JavaScript代码),并且通过组合选项,你可以进行轮询.
在我们的演示中:
PHP 任务follow.php
<?php
require("Sync.php");
$shared = new Sync("some_file.txt");
if ($shared->progress !== null) {
echo $shared->progress;
}
Run Code Online (Sandbox Code Playgroud)
HTML UI的domajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>My Task!</title>
</head>
<body>
<a
href="#"
id="run-task"
class="domajax click"
data-endpoint="task-launch.php"
data-domajax-complete="#polling"
>Run task</a>
<div
id="polling"
data-endpoint="task-follow.php"
data-delay="1000"
data-output-not-empty="#task-progress-pct"
data-domajax-not-empty=""
></div>
<div id="task-progress">Progression: <span id="task-progress-pct">--</span>%
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//domajax.com/js/domajax/jquery.domajax.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
如您所见,此代码中根本没有可见的javascript.干净不是吗?
其他示例可在domajax的网站上找到,请查看演示窗格中的"轻松管理进度条"选项卡.所有选项都有详细记录以供详细说明
Jim*_*ell 27
你实际上不需要 Javascript来完成这个.如果您正在等待的任务是持久的,您只需创建一个PHP脚本:
您可以使用HTML元刷新进行非JavaScript刷新.它可能看起来像这样(在10年内没有完成PHP,所以像伪代码一样对待它):
<?php
$taskId = $_GET("taskId");
$task = lookupTask($taskId);
$refresh = $task->percentComplete < 100;
?>
<html>
<head>
<? if($refresh): ?>
<meta http-equiv="refresh" content="5">
<? else: ?>
<meta http-equiv="refresh" content="0; url=taskComplete?taskId=<?=$taskId ?>" />
<? endif; ?>
</head>
<body>
Loading: <?=$task->percentComplete ?>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
另一种方法,一个非常难看的黑客,将使用PHP的flush()方法.Flush会强制当前输出缓冲区运行PHP(例如CGI).此输出有时会被主机应用程序进一步缓冲,但在某些Web服务器上,它会将输出直接发送给用户.在这里阅读更多:http://php.net/manual/en/function.flush.php
您可能需要将它与ob_flush结合使用,但我不是肯定的:http://php.net/manual/en/function.ob-flush.php
使用CSS,您可以默认隐藏所有"加载"文本,但是覆盖最后一个子加载文本并显示它.例如:
<style type="text/css">
.loadText {
display: none;
}
.loadText:last-child {
display: block;
}
</style>
<?php
for ($x = 0; $x <= 100; $x++) {
echo '<div class="loadText">Loading: ', $x, '%</div>';
flush();
}
?>
Run Code Online (Sandbox Code Playgroud)
这两种解决方案都很糟糕,我只想分享它们的完整性:)
Lif*_*ery 11
详细说明这里的答案;
PHP是一种服务器端语言,但这不是它通常无法正常工作的原因.
这与我们通过HTTP协议进行通信的方式有关.
当客户端向服务器发送HTTP请求时,首先发生的是他们建立连接.然后,服务器处理请求并生成响应,然后将响应发送回客户端.
一旦收到响应,连接就会消失.
因此,通常,每个请求都会收到一个响应.
一个常见的误解是使用现在默认的keep-alive标头进行持久连接,您可以在套接字保持打开时继续推送内容.HTTP实际上不会以这种方式工作,并且在您可以流式传输数据之前需要更多操作.
但更多关于这里和这里.
你能做什么?
我能想到几个选项.
XMLHttpRequest对象,以根据我们收到的每个响应来查询服务器,从而有效地创建媒体流.最后,您可能想要阅读通过其中一些技术的流行答案.
更简单:
<style> div:not(:last-child) { display:none } </style>
<?php
$x=1;
while($x<=100) {
echo "<div>Loading: $x %</div>";
$x++;
}
?>
Run Code Online (Sandbox Code Playgroud)
这样,当新的<div>s出现时,旧s将被隐藏.
| 归档时间: |
|
| 查看次数: |
19145 次 |
| 最近记录: |