PDA

View Full Version : آموزش: افزایش سرعت بارگزاری صفحات php و html با چند تکنیک ساده



AMIBCT
یک شنبه 19 تیر 1390, 23:19 عصر
افزون بر تکنیک‌هایی که کارایی و سرعت تولید محتوا را زیاد می‌کنند، چند تکنیک بدون هزینه نیز وجود دارند که می‌توانند سبب کم‌شدن زمان انتظار مشتری برای بارگزاری صفحه شوند.

محتوایی که توسط php تولید و به مرورگر ارسال می‌شود، پیش از ارسال به مرورگر در بسته‌هایی با حجم مشخص قرار می‌گیرند و اگر حجم آن زیاد نباشد، معمولا پیش از پایان اسکریپت به مرورگر فرستاده نمی‌شوند.

یکی از ساده‌ترین کارهایی که برای افزایش سرعت می‌توان به انجام رساند، استفاده از دستور «flush» پس از پایان تگ «head» در HTML است. دستور flush در php باعث می‌شود محتوای تولیدشده تا کنون فورا برای مرورگر فرستاده شود. با توجه به اینکه معمولا بخش head حاوی پیوند به فایل‌های دیگر مانند فایل‌های css و اسکریپت‌ها و … است. ارسال فوری آن باعث می‌شود تا مرورگر دریافت این فایل‌ها را زودتر آغاز کند و زمان انتظار برای دریافت محتوای صفحه به بهترین شکل ممکن مورد استفاده قرار گیرد.

برای پیاده‌سازی این تکنیک، قطعه کد زیر را درست بعد از تگ پایان «head» فراخوانی کنید

<?php flush(); ?>

نکته‌ی ساده‌ی بعدی، قرار دادن تگ‌های «style» در بخش «head» است ( مگر در زمانی که این کار ممکن نباشد ). این کار سبب می‌شود، کارایی تکنیک قبلی به بیشینه‌ی خود برسد و علاوه بر آن، هنگامی که مرورگر خصوصیات css عناصر را از پیش بداند، محاسبات سنگین و زمان‌بر تعیین حالت نمایش به حداقل خود می‌رسد.

برخلاف تگ‌های Style، بهتر است تا تگ‌های Script را در انتهای فایل خود قرار دهید( مگر زمانی که این کار ممکن نباشد ). علت این امر خاصیت ویژه‌ی اسکریپت‌ها است. مطابق استانداردهای موجود، تا زمانی که یک اسکریپت بارگزاری نشود، دریافت فایل‌های دیگر متوقف می‌ماند و ادامه‌ی دریافت و پردازش آن‌ها وابسته به پردازش فایل اسکریپت می‌شود.

بهینه‌سازی بعدی استفاده از کمترین تعداد فایل‌های خارجی است. به این معنی که تا جایی که امکان دارد، از فایل‌های خارجی -مانند Styleها و Script- کمتری استفاده کنید. با یکی کردن محتوای این فایل‌ها، تعداد درخواست‌های http به حداقل می‌رسد و سرعت بارگزاری صفحه‌ی شما زیادتر می‌شود.

از قرار دادن قالب‌بندی‌های درون‌خطی خودداری کنید و تمام قالب‌بندی‌ها را به فایل‌های css منتقل کنید. این‌کار علاوه بر حذف موارد تکراری، سبب کاهش حجم html اصلی و افزوده‌شدن قابلیت Caching به قالب‌بندی‌ها می‌شود.

منبع:
http://amib.ir/weblog/?p=147

eshpilen
دوشنبه 20 تیر 1390, 09:59 صبح
خیلی دوست داشتم دستور flush کار میکرد، اما متاسفانه کار نمیکنه.
فکر میکنم بخاطر این باشه که آپاچی هم خروجی رو بافر میکنه.
و البته چند چیز دیگه هم میتونه جلوی تاثیرش رو بگیره.
به این مسائل در منوال این تابع (http://php.net/manual/en/function.flush.php) هم اشاره شده.

مثال:


<?php

echo "<b>1</b>\r\n";
flush();
sleep(5);
echo "<b>2</b>\r\n";

?>

الان اگر تابع flush درست کار بکنه ما باید 1 رو در صفحهء مرورگر ببینیم و بعد از 5 ثانیه 2 رو.
ولی 1 و 2 هردو با هم بعد از 5 ثانیه دیده میشن.

بخش کامنتهای منوال رو میخونم شاید راهکاری براش ارائه کرده باشن که عملی باشه.
شما هم راه حلش رو پیدا کردید بگید خب.

AMIBCT
دوشنبه 20 تیر 1390, 11:06 صبح
ممکنه آپاچی هم بافری برای خودش داشته باشه

ولی این آزمایش شما تایید کننده‌ی این بافر نیست
به دلیل اینکه مرورگر هر حرفی رو که دریافت می‌کنه دلیلی نداره نشونش بده
می‌تونه اون رو پردازش کنه ولی نمایشش رو موکول کنه به بسته شدن تگ انتهایی یا هزار مسئله‌ی دیگه
مرورگر خیلی پیچیده هست و با این آزمایش ساده نمی‌شه به نتیجه رسید

eshpilen
دوشنبه 20 تیر 1390, 19:00 عصر
بنده کامنتهایی رو که پای رفرنس تابع flush زده بودن خوندم.
اولا باید بگم واقعا چقدر این کامنتها غنی هستن، در عین اینکه حجم دارن.
یعنی خودش مثل یه رفرنس و کتاب آموزش برنامه نویسی هست.
و این یکی از دلایل رشد و غنای بازمتن و فرهنگ اونه و بخاطر سیاست باز نرم افزارهای آزاد و بازمتن تقویت هم میشه. خود کاربران نقش تکمیل و اصلاح و غنی کردن رفرنس و یه منبع اطلاعات و ترفندهای برنامه نویسی خیلی خوب رو فراهم میکنن.
واقعا آدم لذت میبره از چیزایی که میخونه. افراد مختلف نمونه کدها و راه حل مشکلات خودشون رو ارائه کرده بودن و گفته بودن این مطالب رو میذارن برای کسانی که ممکنه نیاز/مشکل مشابهی داشته باشن. بعضی ها هم گفته بودن بخاطر اینکه مدیون community هستن و ازش چیزی یاد گرفتن میخوان چیزی هم بهش برگردونن.
این فرهنگ و پدیدۀ زیبا رو ما نباید فراموش کنیم و کم ارزش بدونیم.

دوما خوشبختانه میشه کاری کرد تابع flush بخوبی کار کنه و حتی برای تفاوتها و رفتار خاص بعضی مرورگرها هم ترفندهای کم و بیش مناسبی رو پیاده کرد. همۀ این موارد رو توضیح نمیدم چون تعداد و ظرافت اونا زیاد هست و الان تست و جمع بندی کامل مطمئنی ندارم. اگر نیاز به این کار داشتید میتونید به کامنتهای رفرنس یا منابع دیگه مراجعه کنید و اگر مشکل داشتید باهم روش بحث و بررسی کنیم.

بنظرم نکتۀ خیلی مهم بین اینا اینه که باید از تابع ob_flush() (http://www.php.net/manual/en/function.ob-flush.php) هم همراه با تابع flush استفاده کنیم.
مثلا بنده به این روش تست کردم و این داستان درست کار کرد:


<?php

echo "1";
@ ob_flush(); flush();
sleep(3);
echo "2";

?>

این کد الان روی فایرفاکس 3.6.8 داره خوب کار میکنه. البته توجه داشته باشید که این فقط یک کد سردستی و آزمایشی هست و با شرایط مختلف بصورت کامل تست نشده؛ نسخۀ حرفه ایش احتمالا باید جزییات بیشتری داشته باشه. فقط خواستم به نقش حیاتی ob_flush() اشاره بکنم.
اما روی بعضی مرورگرها بخصوص IE و بخصوص نسخه های قدیمی تر اون این کد جواب نمیده چون این مرورگرها بقول شما خودشون چیزی رو که دریافت میکنن فورا نشون نمیدن. اما برای اینهم راهکار وجود داره، مثلا فرستادن یکسری کاراکتر فاصله اضافی. مثلا بعضی مرورگرها نیاز دارن حداقل تعداد خاصی کاراکتر رو دریافت بکنن تا شروع به نمایش اطلاعات بکنن. ضمنا بعضی نکات دیگه هست مثل اینکه IE میتونه در جدولها مشکل داشته باشه؛ یعنی اینکه تا تگ انتهایی جدول رو (</table>) دریافت نکنه چیزی نشون نمیده. خلاصه برای اینکه برنامتون کامل باشه نهایتا باید اون رو حداقل روی چند مرورگر معروف تست کنید و ترفندهای لازم برای هر مرورگری رو به کدهاتون اضافه کنید. میتونید نمونه های مختلف این ترفندها و کدها رو در کامنت های منوال مشاهده کنید. بنده چون کامل تست و بررسی نکردم نمیدونم کدومشون صحیح ترین و کاملترین و بهترین راه هست.
یه نکتۀ دیگه هم که یادم رفت بگم اینه که flush کردن ممکنه بر اثر چیزهایی مثل فشرده سازی سمت سرور هم بی اثر بشه که برای اینهم راهکار و نمونه کد درج شده.

راستی چنتا کار قشنگ توی این کدها رو معرفی میکنم ببینید:

اینو با فایرفاکس تست کنید (با IE8 تست کردم درست کار نمیکنه):

<?php
header('Content-type: multipart/x-mixed-replace;boundary=endofsection');
print "\n--endofsection\n";

$pmt = array("-", "\\", "|", "/" );
for( $i = 0; $i <10; $i ++ ){
sleep(1);
print "Content-type: text/plain\n\n";
print "Part $i\t".$pmt[$i % 4];
print "--endofsection\n";
ob_flush();
flush();
}
print "Content-type: text/plain\n\n";
print "The end\n";
print "--endofsection--\n";
?>

این یکی هم روی فایرفاکس و هم روی IE8 کار میکنه:


<html>
<head>
<style type="text/css"><!--

div {
margin: 1px;
height: 20px;
padding: 1px;
border: 1px solid #000;
width: 275px;
background: #fff;
color: #000;
float: left;
clear: right;
top: 38px;
z-index: 9
}

.percents {
background: #FFF;
border: 1px solid #CCC;
margin: 1px;
height: 20px;
position:absolute;
width:275px;
z-index:10;
left: 10px;
top: 38px;
text-align: center;
}

.blocks {
background: #EEE;
border: 1px solid #CCC;
margin: 1px;
height: 20px;
width: 10px;
position: absolute;
z-index:11;
left: 12px;
top: 38px;
filter: alpha(opacity=50);
-moz-opacity: 0.5;
opacity: 0.5;
-khtml-opacity: .5
}

-->
</style>
</head>
<body>

<?php

if (ob_get_level() == 0) {
ob_start();
}
echo str_pad('Loading... ',4096)."<br />\n";
$d=0;
for ($i = 0; $i < 25; $i++) {
$d = $d + 11;
$m=$d+10;
//This div will show loading percents
echo '<div class="percents">' . $i*4 . '%&nbsp;complete</div>';
//This div will show progress bar
echo '<div class="blocks" style="left: '.$d.'px">&nbsp;</div>';
flush();
ob_flush();
sleep(1);
}
ob_end_flush();
?>
<div class="percents" style="z-index:12">Done.</div>
</body>
</html>

یک کاربرد مهم این قضیه هم فکر میکنم در Comet (http://en.wikipedia.org/wiki/Comet_%28programming%29) باشه.

eshpilen
دوشنبه 20 تیر 1390, 19:16 عصر
ممکنه آپاچی هم بافری برای خودش داشته باشه

ولی این آزمایش شما تایید کننده‌ی این بافر نیست
به دلیل اینکه مرورگر هر حرفی رو که دریافت می‌کنه دلیلی نداره نشونش بده
می‌تونه اون رو پردازش کنه ولی نمایشش رو موکول کنه به بسته شدن تگ انتهایی یا هزار مسئله‌ی دیگه
مرورگر خیلی پیچیده هست و با این آزمایش ساده نمی‌شه به نتیجه رسید البته حق با شماست و بنده هم از این احتمال اطلاع داشتم، ولی خوشبختانه ظاهرا بافر مربوط به خود PHP بود که با ob_flush حل میشه. اگر از آپاچی بود میتونست مشکل خیلی سخت تری برای حل کردن بشه.
البته غیر از آپاچی، سرویس دهنده های دیگری هم ممکنه بین راه باشن که بافر و ایجاد مشکل کنن.
مسئلۀ رفتار خاص هر مرورگر بعد از این مرحله هست که اون رو هم باید تست کرد و میشه با ترفندهای مربوطه حلش کرد.
تاجاییکه خوندم و تست کردم، فایرفاکس فعلی در این زمینه مرورگر خیلی خوبی هست، اما درمورد IE و بعضی مرورگرهای دیگر رفتارهای دردسرساز متنوعی وجود داره.


یکی از ساده‌ترین کارهایی که برای افزایش سرعت می‌توان به انجام رساند، استفاده از دستور «flush» پس از پایان تگ «head» در HTML است. دستور flush در php باعث می‌شود محتوای تولیدشده تا کنون فورا برای مرورگر فرستاده شود. با توجه به اینکه معمولا بخش head حاوی پیوند به فایل‌های دیگر مانند فایل‌های css و اسکریپت‌ها و … است. ارسال فوری آن باعث می‌شود تا مرورگر دریافت این فایل‌ها را زودتر آغاز کند و زمان انتظار برای دریافت محتوای صفحه به بهترین شکل ممکن مورد استفاده قرار گیرد.
فکر نمیکنم این عمل درمورد کاربردهای معمولی تاثیر مشهودی داشته باشه. وقتی زمان پردازش یک صفحه زیر یک ثانیه یا حتی کمی بیشتر هست، ارسال زودتر یا دیرتر هم در همین حدود خواهد بود و بنابراین تاثیر خاصی نداره.
بنظر بنده این متد بیشتر درمورد صفحاتی که پردازشهای خیلی سنگینی که زیاد طول میکشه یا عملیاتی که ماهیتا زمانبر هست انجام میدن مفیده.
البته کاربرد دیگرش رو هم که اشاره کردم در ساخت برنامه هایی با مدل Comet (http://en.wikipedia.org/wiki/Comet_%28programming%29) و اینطور چیزها هست.