PHP 執(zhí)行代碼的方式是同步串行的,也就是說,PHP 中定義的操作代碼會一個接一個的逐步完成。如果我們需要在一個會話中執(zhí)行大量操作,或者調(diào)用外部 API,這種同步執(zhí)行代碼的方式可能需要比較長的時間,從而造成用戶等待時間過長。這是一個很糟糕的用戶體驗,在本文中,我們來看一下怎么異步執(zhí)行耗時較長的操作。
使用 WP Cron 在 WordPress 中異步執(zhí)行 PHP 任務(wù)
我們知道,WordPress 為我們提供了 WP Cron 系統(tǒng),來幫助我們實現(xiàn)定時操作。我們實現(xiàn)異步 PHP 的方式就是把一些操作加入當(dāng)前時間點后面的一次性任務(wù)計劃中,從而推遲一些不需要立即有結(jié)果的操作。
比如 WordPress 發(fā)表評論時發(fā)送通知郵件給管理員的操作,默認(rèn)情況下,這個操作是同步執(zhí)行的,郵件必須發(fā)送成功后,系統(tǒng)才會提示用戶評論成功,而在有些主機上,發(fā)送郵件會比較慢,這就導(dǎo)致了比較長的用戶等待時間。
實際上,管理員并不需要立即收到通知郵件,就算收到了,管理員也不一定有時間馬上處理。所以,我們可以先提示用戶評論成功,然后,等到設(shè)置的發(fā)送郵件任務(wù)計劃時間到了,再發(fā)送通知郵件。
下面的函數(shù)實現(xiàn)了一個簡單的異步發(fā)送郵件的功能:
if ( ! defined( 'DOING_CRON' ) || ( defined( 'DOING_CRON' ) && ! DOING_CRON ) ) {
function async_send_wp_mail() {
// 獲取 wp_mail 函數(shù)的參數(shù)
$args = func_get_args();
// 添加一個隨機值以避免重復(fù)發(fā)送,參考: http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
$args[] = mt_rand();
// 5 分鐘之后發(fā)送郵件
wp_schedule_single_event( time() + 5, 'cron_send_mail', $args );
}
}
發(fā)送郵件的時候,我們可以使用以下代碼異步發(fā)送郵件。
add_action( 'cron_send_mail', function () {
$args = func_get_args();
// 移除上面添加的隨機數(shù)
array_pop( $args );
call_user_func_array( 'wp_mail', $args );
}, 10, 10 );
使用 WP Asynchronous Tasks 庫在 WordPress 中實現(xiàn)異步 PHP 操作
使用 WP Cron 異步發(fā)送郵件的方法相當(dāng)簡單,但是會有一些效率問題,當(dāng)郵件比較多時,延時可能會比較大。TechCrunch 開源的 WP Asynchronous Tasks 庫解決了這個問題,實現(xiàn)方法是,在任務(wù)執(zhí)行時,添加一個隨機數(shù)作為任務(wù)標(biāo)記,通過這個隨機數(shù)來驗證任務(wù)是否執(zhí)行成功,如果執(zhí)行成功,就接著執(zhí)行推后的任務(wù)。
比如,在文章頁面,我們需要獲取幾篇和當(dāng)前文章?lián)碛泄餐诸惢驑?biāo)簽的文章,作為相關(guān)文章顯示,這是一個比較耗時的 MySQL 查詢,我們一般需要使用緩存來優(yōu)化。當(dāng)緩存中有這個數(shù)據(jù)的時候,就直接顯示緩存中的數(shù)據(jù),如果緩存中沒有這個數(shù)據(jù),或者緩存已過期,則獲取數(shù)據(jù)、加入緩存,然后再顯示。
因為這是一個耗時的操作,在瀏覽比較大的站點上。如果先更新緩存再顯示出來,用戶等待的時間可能會比較長。在這個操作上,我們就可以使用異步的方式來優(yōu)化這個操作,在顯示頁面的時候,直接顯示緩存中的數(shù)據(jù),同時判斷一下緩存到期時候,如果快到期了,則添加一個異步任務(wù)來更新緩存。這樣,頁面中顯示的永遠(yuǎn)是緩存的數(shù)據(jù)。
根據(jù) TechCrunch 的說明,在合適的時機使用?WP Asynchronous Tasks 可以提升WordPress頁面的加載速度到原來的 5-8倍,如果你的站點遇到了這方面的問題,可以考慮使用這個庫來進(jìn)行優(yōu)化。
另外一個類似的庫是 WP Migrate DB Pro 開發(fā)商開發(fā)的 WP Background Processing 庫,該庫在 WP Asynchronous Tasks 的基礎(chǔ)上,增加了簡單的任務(wù)隊列支持。如果需要執(zhí)行大量的耗時重復(fù)操作,我們需要的可能是基于數(shù)據(jù)庫的完整 WordPress 任務(wù)隊列。
