全て、
問題発見の経緯
私の質問は、Web アプリ、主にインデックス ページのパフォーマンスに関するものです。Google の読み込みに約 10 秒かかるという事実から判断すると、インターネットが遅い (正確な速度や ping レートはわかりません) 私の会社の支社でデモンストレーションを行っていたときに、この問題に気付きました。インデックス ページの読み込みに 10 ~ 20 倍の時間がかかりました。私は、自分のアプリがサーバー側でほとんどの作業を行っていると想定していました (php がすべてのデータベースクエリを作成しているため...)。しかし、これにより、Chrome のネットワーク ツールを調べて、これら 4 つの div が ajax によって読み込まれるまでの待ち時間を確認することができました (後で詳しく説明します)。興味深いことに、呼び出されるスクリプトは順番に実行されるように見えますが、必ずしも ajax 呼び出しを呼び出した順序とは限りません (実行される場合と実行されない場合があります)。
これらの div / ajax リクエストとは何ですか?
リクエストのコード スニペットを次に示します。
Yii::app()->clientScript->registerScript('leftDiv', '
$( "#left_dash" ).load(
"'.$this->createUrl("/site/page?view=leftDashLoad") .'",
function(){
$("#left_dash p a").click(function() {
$(this).parent().parent().find("div.scroll100").slideUp();
$(this).parent().next().stop(false, false).slideDown();
});
$("p:first-child").next().slideDown();
}
);
' );
リクエストされたページは次のとおりです。
$this->widget('widgets.ScrollList',array(
'condition'=>
function($muddJob,$scrollList)
{
$job = $muddJob->Job;; //returns a job or empty array
if(!empty($job) )
{
if( $muddJob->uploadArtwork == null && $muddJob->uploadData == null ) {
array_push($scrollList->_models,$job);
$scrollList->columnValues = array($muddJob->jobDescription,$muddJob->dropDate1);
return true;
}
}
return false;
},
'columns' => array('col1'=>"MuddJob#",'col2'=>"Desc",'col3'=>"Dealer Name"),
'name'=> "Print New Ticket",
'muddJobs' => $currentExchanges->getCurrentMuddExchanges(),
)
);
そのページ (ajax が呼び出したページ) に、ウィジェットを作成する 6 つの同様の宣言があると想像してください。目標は、html を返して、読み込み中の gif の代わりにインデックス ページに戻すことです。
スクロール ウィジェットは次のとおりです。
<?php
Yii::import('widgets.ScrollListBase');
include_once Yii::app()->extensionPath . "/BusinessDay.php";
class ScrollList extends ScrollListBase
{
private $_content;
public $columns = array();
public $columnValues;
private $_listInfo;
public $name;
public $_models = array();
public $condition;
public $muddJobs; //object to pass
public $jobsMailingTodayArray = array();
public function init()
{
//$this->init();
$this->_listInfo = $this->generateListInfo($this->columns);
//$muddJobs = $this->getCurrentMuddExchanges();
$listInfo = $this->newScrollList($this->muddJobs);
$contents = $this->createContent($listInfo,$this->name);
$this->_content = $contents[0];
// $this->_fullTableContent = $contents[1];
//$this->_listInfo = $contents[2];
}
public function run()
{
//if($this->data['isVisible'])
echo $this->_content;
Yii::app()->session["exploded_content_{$this->name}"] = $this->_models;
}
private function newScrollList($muddJobs)
{
$listInfo = $this->_listInfo;
$tempCount = 0;
foreach($muddJobs as $muddJob)
{
$condition = $this->condition;
if($condition($muddJob,$this) && empty($this->jobsMailingTodayArray) ) //if no job exists for the muddExchange...
{
$tempArray = $this->createWidgetLinks($tempCount,$listInfo,$muddJob,$this->columnValues);
$listInfo = $tempArray[0];
$tempCount = $tempArray[1];
}
elseif ( !empty($this->jobsMailingTodayArray ) )
{
foreach ($this->jobsMailingTodayArray as $jobMailingToday) //change to for loop over the length of the jobsMailingToday
{
$tempArray = $this->createWidgetLinks($tempCount,$listInfo,$muddJob,$this->columnValues);
$listInfo = $tempArray[0];
$tempCount = $tempArray[1];
}
$this->jobsMailingTodayArray = array();
}
}
return array($listInfo,$tempCount);
}
}
?>
これがその親です:
<?php
class ScrollListBase extends CWidget
{
private $content = "<p>";
private $divDeclaration = "<div class='scroll100'>\n<table class='quickInfoTable'>\n<thead>\n";
private $headTag = "<th>";
private $headTagClose = "</th>\n";
private $theadTagClose = "</thead>\n";
private $bodyTag = "<tbody>\n";
private $listInfo = "<div class='scroll100'>\n<table class='quickInfoTable'>\n<thead>\n<th>Job#</th>\n<th>Package#</th>\n<th>Entry Date</th>\n</thead>\n<tbody>\n";
/**
* Initializes the widget.
*/
public function createContent($listInfo,$name)
{
$largeHref = Yii::app()->request->baseUrl . '/index.php/site/fullTableView';
$this->content .= "<span class='badge' >{$listInfo[1]} </span> <a href='#'>{$name} </a> <a href='$largeHref/Name/{$name}'> <small>(view larger)</small> </a> </p>";
if( $listInfo[1] > 0 )
{
// $this->fullTable .= substr($listInfo[0],22);
// $this->fullTableContent= $this->fullContent .= $this->fullTable . "</tbody>\n</table>\n</div>";
$this->content .= $listInfo[0] . "</tbody>\n</table>\n</div>";
}
return array($this->content);
}
//Helper Methods
/**
*
* @param type $attributeArray. send an accociative array
* @return type = either a job or an empty array
*/
protected function getJobByAttributes($attributeArray)
{
return Jobs::model()->with('MuddExchange')->findByAttributes($attributeArray);
}
protected function createWidgetLinks($tempCount,$listInfo,$muddJob,$columnValues,$url="/MuddExchange/")
{
$tempCount++;
$viewIndex = $muddJob->exchange_id;
$model = $muddJob;
$job = $muddJob->Job;
if ( isset($job ))
{
$model = $job;
$url = "/Jobs/";
$viewIndex = $model->job_id;
}
$link = CHtml::link("$model->jobNumber",array("{$url}{$viewIndex}"));
$listInfo .= "<tr>\n<td>$link</td>\n";
foreach ($columnValues as $columnValue)
{
$listInfo .= "<td>{$columnValue}</td>\n";
}
$listInfo .= "</tr>";
return array($listInfo,$tempCount);
}
protected function getListInfo()
{
return $this->listInfo;
}
/**
* Takes an array of strings to generate the column names for a particular list.
* @param array $heads
* @return string
*
*/
protected function generateListInfo($heads)
{
//<th>Job#</th>\n<th>Package#</th>\n<th>Entry Date</th>\n</thead>\n<tbody>\n";
$htmlScrollStart = $this->divDeclaration;
foreach ($heads as $tableColumn => $name)
{
$htmlScrollStart .= $this->headTag . $name . $this->headTagClose;
}
$htmlScrollStart .= $this->theadTagClose . $this->bodyTag;
return $htmlScrollStart;
}
public function calculateDueDate($jobsMailDate,$job)
{
$package = PackageSchedule::model()->findByAttributes(array('package_id'=>$job->packageID));
$projectedDays = $package->projected_days_before_mail_date;
$dropDate1 = $jobsMailDate->projected_mail_date;
$dropDate = wrapBusinessDay($dropDate1); //use this for actual command...
$toSec = 24*60*60;
$dayInt =0;
$secDropDate = strtotime($dropDate1);
do{
$dayInt +=1;
$daysInSec = ($dayInt) * $toSec ;
$secGuessDueDate = $secDropDate - $daysInSec;
$dueDate = date('Y-m-d',$secGuessDueDate);
$difference = $dropDate->difference($dueDate);
}while( $difference != $projectedDays);
return $dueDate;
}
}
?>
この行動がおかしいと思う理由
遅いインターネット全体はそれ自体が獣ですが、それが StackOverflow の範囲内にあるとは思いません。これらの div の読み込みについてもっと心配しています。最後にロードする、つまり平均 1.5 ~ 2 秒かかる div は、単一のウィジェットを作成するページへの ajax リクエストです。その背後にあるロジックは次のとおりです。
<?php
include_once Yii::app()->extensionPath . "/CurrentExchanges.php";
$currentExchanges = Yii::app()->session['currentExchanges'];
$this->layout = 'barebones';
$this->widget('widgets.ScrollList',array(
'condition'=>
function($muddJob,$scrollList)
{
if ($muddJob->dropDate1 != null && $muddJob->dropDate1 != '0000-00-00')
{
$job = $muddJob->Job;;
if(!empty($job) && $job->packageID != null) //if job exists for the muddExchange and has a package
{
if($job->uploadArtwork == null )
{
$jobsMailDate = JobsMailDate::model()->findByAttributes(array("job_id"=>$job->job_id,'sequence_num'=>1));
if(!empty($jobsMailDate))
{
$calculatedDueDate = $scrollList->calculateDueDate($jobsMailDate,$job);
if (strtotime($calculatedDueDate) <= strtotime(date("Y-m-d")) )
{
array_push($scrollList->_models , $job);
$scrollList->columnValues = array($muddJob->jobDescription,$muddJob->dropDate1,$jobsMailDate->projected_mail_date);
return true;
}
}
}
}
}
return false;
},
'columns' => array('col1'=>"MuddJob#",'col2'=>"Desc",'col3'=>"Drop Date", 'col4' =>'Projected Drop Date'),
'name'=> "Artwork Due Today",
'muddJobs' => $currentExchanges->getCurrentMuddExchanges(),
)
);
?>
Calculateduedate メソッドは、サーバーに対して 2 つの追加の呼び出しを行います。
私が理解できていないのは、左の div (最も多くの処理を行う) が通常最初に返され、artLoad が通常最後に読み込まれる理由です (実質的な違いによる)。chromes ネットワーク ツールによって返される時間は次のとおりです。
leftDashLoad: 475ms
rightDashLoad: 593ms
dataLoad: 825ms
artLoad: 1.41s
dataLoad: 453ms
rightDashLoad: 660ms
leftDashLoad: 919ms
artLoad: 1.51s
rightDashLoad: 559ms
leftDashLoad: 1.17s
dataLoad: 1.65s
artLoad: 2.01s
左/右のダッシュロードが artLoad よりもはるかに速く返される理由がわかりません。artLoad と dataLoad のコードは、実際の比較 (if ステートメント) を除いてほぼ同じです。これが本当に非同期である場合、各ページで実行される計算量のみに基づいて、art/dataLoad、rightDashLoad、および leftDashLoad の順序になると思います。おそらく、サーバーがマルチスレッド化されていないか、奇妙な構成が存在しますが、そうであれば、インターネットの速度が遅いためにロードの影響がなぜそれほど大きな打撃を受けるのかわかりません. 明らかなことを見落としたり、Google を適切に使用できなかったりした場合は、お詫び申し上げます。ご協力いただきありがとうございます。
言語/その他の技術情報
このアプリは、Yii フレームワークを使用して開発されました。PHP 5.3。アパッチサーバー。INNODB テーブル。サーバーはdreamhostでホストされています。
アップデート
ビュー ページを変更して、ajax 呼び出しがコントローラー アクションを呼び出すようにしました。私のローカル開発環境ではロード時間がより類似した(非同期?)ようになったようですが、QA環境(dreamhostでホストされている...)では実際に遅くなりました。ローカル ネットワーク ツール情報のスクリーン ショットを次に示します。
およびqaサイト(データベースにはほぼ同じ量のデータがあることに注意してください...)
考え?(私のローカル dev での) 戻り時間は、私が期待するように見えるので、私の元の問題は解決されるかもしれません。
また、xdebug がセッションを使用しているため、NetBeans のデバッグ方法に関する私自身の無知が、この同期読み込みに関与していました。これにより、ajax呼び出しが順番を待つようになったと思います。