我正在使用 PHP 脚本来最小化 javascript。问题是脚本在服务器响应之前经常需要一秒钟左右的时间,这几乎完全违背了目的。即使只是发送一个 304,有时仍然需要一秒钟左右的时间来发送响应,在此期间浏览器处于挂起状态。
加载时,脚本功能如下:
- 根据查询字符串 var 确定要加载的文件(或文件)(如果查询字符串 var 为空,则使用默认值)
- 检查文件的缓存副本是否可用并且是最新的(这是存储在服务器上的 .txt 文件)
- 如果是这样,什么也不做。如果没有,则创建或重新创建缓存文件(我使用 JShrink 0.5.1 进行缩小)
- 最后,检查缓存文件的 etags 和 last-modified 是否与用户的匹配
- -- 如果是这样,只需发送 304
- -- 如果没有,在缓存文件上做一个 readfile
它不会始终如一地执行此操作 - 一次刷新可能需要一秒钟,下一次大约需要 100 毫秒,两者都返回 304。由于不一致,我最好的猜测是延迟访问缓存文件硬盘驱动器(即使发送 304,它仍然必须对缓存文件和 $fileList 中的任何文件执行 filemtime(),然后对缓存文件执行 md5_file() 以生成当前 etag)。
关于如何解决这个问题的任何想法?以下是一些相关的代码块:
<script type="text/javascript" src="/loadJS.php"></script>
// steps 2 and 3 (check cache, update if necessary, fileList is an array of paths to .js files):
if ( file_exists( $cacheFile ) ) {
$cacheLastModified = filemtime( $cacheFile );
for( $i = 0; $i < sizeof( $fileList ); $i++ ) {
/* check if any files in the list are newer than the cache's last modification date
* if so, cache must be updated
*/
if ( $cacheLastModified < filemtime( $fileList[$i] ) ) {
$outdated = true;
}
}
}
if ( isset( $outdated ) || !file_exists($cacheFile) ) {
// update the cache file now
ob_start();
foreach( $fileList as $file ) {
readfile( $file );
}
$output = ob_get_clean();
include( "includes/JShrink-0.5.1.class.php" );
$output = Minifier::minify($output, array('flaggedComments' => false));
if ( $cacheFileFP = fopen( $cacheFile, "w" ) ) {
if ( fwrite( $cacheFileFP, $output ) ) {
fclose( $cacheFileFP );
} else {
// handle fwrite errors
}
} else {
// handle fopen errors
}
}
// step 4 (function checks etags and modification date):
function fileNotModified ( $file ) {
/* returns false if file NOT modified
* -- or an array of headers if file has been modified
* use two criteria to determine if file has been modified
* a) if-modified-since header vs the file's last-modified time
* b) etag match
* if if-modified-since is the same as file mod time, or etags match
* --- return array of headers to send
* else return false
*
* see http://stackoverflow.com/questions/2000715/answering-http-if-modified-since-and-http-if-none-match-in-php/2015665#2015665
*/
$gmtModifiedTime = gmdate('r', filemtime($file) );
$eTag = md5_file( $file );
$result = false;
if( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) || isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
if ( $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmtModifiedTime || str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == $eTag ) {
$result["ETag"] = $eTag;
$result["Last-Modified"] = $gmtModifiedTime;
}
}
return $result;
}
// steps 5 and 6 (304 header or send readfile output):
if ( $headers = fileNotModified( $cacheFile ) ) {
// send the headers and 304 not modified
foreach( $headers as $name=>$value ) {
header( $name . ": " . $value );
}
header('HTTP/1.1 304 Not Modified');
/*exit();*/
} else {
// read and output the cache
header("Last-Modified: " . gmdate("r", filemtime( $cacheFile )) );
header("Etag: " . md5_file( $cacheFile ) );
readfile( $cacheFile );
}