通过AJAX调用PHP随机生成器的输出结果

3

当前设置: 在同一个PHP文件中,我有一个PHP随机生成器函数和调用该函数的HTML - 一个包含被PHP函数调用的字符串的独立txt文档。

函数

<?php
function rand_line($fileName, $maxLineLength = 4096) {
  $handle = @fopen($fileName, "strings.txt");
  if ($handle) {
    $random_line = null;
    $line = null;
    $count = 0;
    while (($line = fgets($handle, $maxLineLength)) !== false) {
      $count++;
      if(rand() % $count == 0) {
        $random_line = $line;
      }
    }
    if (!feof($handle)) {
      echo "Error: unexpected fgets() fail\n";
      fclose($handle);
      return null;
    } else {
      fclose($handle);
    }
    return $random_line;
  }
}
?>

我在 HTML 中使用以下方式调用函数:

<?php echo rand_line("strings.txt");?>
<input type="button" value="Another String" onClick="window.location.reload()">

这段代码在多个用户访问页面并按下按钮获取新状态时往往会变慢。
我想达到的目标是:提高性能,使整个过程不那么沉重:也许随机器过于复杂,可以使用 AJAX 调用等方法,但如果可能的话,保持字符串列表在 strings.txt 文件中,并与 PHP 脚本和 HTML 分离。
抱歉,如果我说得不对,请谅解... 我不是熟练的程序员。只是偶尔拼凑东西的人 :)

分离你的函数和HTML代码的答案对你来说可接受吗? - dokgu
strings.txt 是否会发生变化?也就是说,它是一个永远不会改变的静态文件吗?还是该文件会不断更新新的字符串?此外,该文件中有多少行/字符串 - mferly
请参考这个答案,获取一个更高效的从文件中随机获取一行的例子,假设您的文件不是非常大(我怀疑您在使用过程中会遇到内存问题)。您目前的算法确实有些绕弯子,进行了不必要的迭代(至少可以在找到内容时停止),并且每次迭代都进行了不必要的工作(每次生成新的随机数,检查是否可被行数整除...)。 - Thernys
@PatrickGregorio 当然可以 :) - Pedro D
如果strings.txt的内容很少更改,您应该考虑将其缓存并从那里进一步访问它们,无限期地。然后在文件添加新内容时允许清除缓存。为什么不只是将它们存储在标准数组中?PHP甚至JavaScript?特别是因为您现在只有约15行,并且不希望在未来超过约100行。每次调用时打开、遍历、随机化、关闭文件都不值得完成它所需的CPU。 - mferly
显示剩余2条评论
3个回答

1

您真的不应该使用window.location.reload();,那太糟糕了...您不应该刷新页面...

location.reload()会发送一个HTTP请求获取整个新页面(完整的HTML),然后不仅您的浏览器需要再次渲染整个HTML,而且您还必须通过网络传输更多重复的数据,从A点到B点。

您应该只发送所需数据的HTTP请求(您不需要再次加载整个HTML,因为您在第一次访问页面时已经加载了它)。

相反,使用XMLHttpRequest JavaScript库(AJAX)仅请求部分数据(在您的情况下=>随机行字符串)

HTML:

<!DOCTYPE html>
<html>
<head lang="en">
    <script type="text/javascript">
        function loadDoc(url, cfunc) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function () {
                if (xhttp.readyState == 4 && xhttp.status == 200) {
                    cfunc(xhttp);
                }
            };
            xhttp.open("GET", url, true)
            xhttp.send();
        }


        function randomLine(xhttp) {
            alert(xhttp.responseText);
        }
    </script>

</head>
<body>

<input type="button" value="Get random line" onClick="loadDoc('http://localhost:8080/myScript.php', randomLine)">

</body>
</html>

PHP:

myScript.php

<?php 
function rand_line($fileName, $maxLineLength = 4096) 
{ 
   ... 
}
echo rand_line("strings.txt");        
?>

@Marcus,我不明白为什么要重新加载整个页面?你能给出一些理由吗?这样做即使所有内容都被缓存且网络上没有额外的数据,浏览器仍然需要渲染HTML和onload-javascript,如果有很多标签,它肯定会明显地减慢页面速度。 - Boy
为什么要浪费额外的资源,完全没有必要。你永远不会知道客户拥有多好的硬件。如果他有一台10年前的电脑,在某些过时的浏览器中打开...对他来说可能是2秒钟,而不是0.5秒。当然,字符串.txt文件中可能有100k行,但我只是假设它是正常大小的文件。唯一可以提高性能的升级就是使用ajax...所以... - Boy
@Marcus 另一个需要注意的问题是用户不喜欢等待页面响应。他们讨厌这个。通过使用 AJAX,我们可以异步地请求数据,同时用户仍然可以使用页面的其他部分。 - Boy
另一个例子可能是网络问题,需要4秒钟才能加载页面。结果就是:用户在空白页面上盯了4秒钟。 - Boy
@Marcus 顺便说一下,试着添加50个html标签(这是一个页面所必需的最低限度),然后告诉我结果...越多的html标签,ajax就越有效。正如你所说,你做了一个测试,在没有使用ajax的情况下加载空白页面需要大约相同的时间。但是这是可以预期的...因为没有任何html标签,浏览器不需要渲染任何html,所以它非常快...但是对于ajax来说,它并不依赖于页面上有多少html,它总是表现得差不多(假设服务器、网络和电脑都是稳定的)。 - Boy
显示剩余7条评论

1

*编辑 #2*

完整运行的脚本。通过 PHP 获取初始 字符串,并将其存储在数组中以供后续 JavaScript 使用。最小化调用次数。

PHP 从文件中获取字符串;生成默认(随机)字符串,并生成一个字符串数组以供稍后使用按钮。

/**
 * @input array $file
 * @return array (mixed) [0] => string, [1] => array
 */
$randomStringFromFile = function($file) {
    if (!$file) return false;

    /**
     * @return Removes carriage returns from the file
     *         and wraps $val with single-quotes so as
     *         to not break JavaScript
     */
    $add_quotes = function(&$val) {
        return str_replace("\n", "", "'$val'");
    };
    return [$file[rand(0, count($file)-1)], array_map($add_quotes, $file)];
};
$randomString = $randomStringFromFile( @file('strings.txt') ) ?: false;

JavaScript

<div id="string_container"><?php echo $randomString[0]; // defaults random string to page ?></div><br>
<button onclick="getString();">Another String</button>
<script>
var getString = function() {
    var arr = [<?php echo implode(',', $randomString[1]); ?>],
        setString = document.getElementById('string_container').innerHTML = arr[Math.floor(Math.random() * arr.length)];
};
</script>

将上述内容放入您的页面中,您就可以开始了。 编辑(原始) 我们可以使用以下方法(最快方法)完全从方程式中删除PHP:
<div id="string_container"></div><br>
<button onclick="getString();">Another String</button>
<script>
var getString = function() {
    var request = new XMLHttpRequest(),
        file = 'strings.txt';

    request.open('GET', file);
    request.onload = function() {
        if (request.status === 200) {
            var arr = request.responseText.split("\n"), /** assuming line breaks in file are standard carriage returns (Unix); "\r" if Windows */
                setString = document.getElementById('string_container').innerHTML = arr[Math.floor(Math.random() * arr.length-1)];
        }
    };
    request.send();
};
</script>

使用PHP的原始文本

我们甚至可以进一步简化PHP,从方程式中完全删除循环。

$randomStringFromFile = function($file) {
    if (!$file) return false;
    return $file[rand(0, count($file)-1)];
};
echo $randomStringFromFile( @file('strings.txt') ) ?: 'No worky!';

使用file()将返回一个数组中的内容,因此您可以简单地随机选择一个键并返回其值。

注意:平均而言,$file[rand(0, count($file)-1)]在随机选择键时优于array_rand()(例如,$file[array_rand($file)];)。两者之间的差距很小,大约是~0.0002秒~0.0005秒


0

你可以简化你的代码

function rand_line($fileName, $maxLineLength = 4096) {
    $f = file($fileName);
    $length = $maxLineLength + 1;

    do {
        $line = $f[array_rand($f)];
        $length = strlen($line);
    } while ($length > $maxLineLength);

    return $line;
}

do {} while (0);,真的。 - Thernys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接