在一般的請求/響應模型中,比如 Web 1.0,客戶機(瀏覽器或者本地機器上啟動並執行代碼)向伺服器發出請求。該請求是同步的,換句話說,客戶機等待伺服器的響應。當客戶機等待的時候,至少會用某種形式通知您在等待:
- 沙漏(特別是 Windows 上)。
- 旋轉的皮球(通常在 Mac 機器上)。
- 應用程式基底本上凍結了,然後過一段時間游標變化了。
這正是 Web 應用程式讓人感到笨拙或緩慢的原因 —— 缺乏真正的互動性。按下按鈕時,應用程式實際上變得不能使用,直到剛剛觸發的請求得到響應。如果請求需要大量伺服器處理,那麼等待的時間可能很長(至少在這個多處理器、DSL 沒有等待的世界中是如此)。
而非同步請求不 等待伺服器響應。發送請求後應用程式繼續運行。使用者仍然可以在 Web 表單中輸入資料,甚至離開表單。沒有旋轉的皮球或者沙漏,應用程式也沒有明顯的凍結。伺服器悄悄地響應請求,完成後告訴原來的要求者工作已經結束(具體的辦法很快就會看到)。結果是,應用程式感覺不 那麼遲鈍或者緩慢,而是響應迅速、互動性強,感覺快多了。這僅僅是 Web 2.0 的一部分,但它是很重要的一部分。所有老套的 GUI 組件和 Web 設計範型都不能克服緩慢、同步的請求/響應模型。
Ajax 和 Web 2.0 最大的秘密是什麼呢?秘密就在於 XMLHttpRequest
的一個簡單屬性 onreadystatechange
。
因為是非同步請求,所以 JavaScript 方法不會等待伺服器。因此代碼將繼續執行,就是說,將退出該方法而把控制返回給表單。使用者可以繼續輸入資訊,應用程式不會等待伺服器。
這就提出了一個有趣的問題:伺服器完成了請求之後會發生什嗎?如果什麼也不發生顯然不行,因此伺服器在完成通過 XMLHttpRequest
發送給它的請求處理之後需要某種指示說明怎麼做。
現在 onreadystatechange
屬性該登場了。該屬性允許指定一個回呼函數。回調允許伺服器反向調用 Web 頁面中的代碼。它也給了伺服器一定程度的控制權,當伺服器完成請求之後,會查看 XMLHttpRequest
對象,特別是 onreadystatechange
屬性。然後調用該屬性指定的任何方法。之所以稱為回調是因為伺服器向網頁發起調用,無論網頁本身在做什麼。比方說,可能在使用者坐在椅子上手沒有碰鍵盤的時候調用該方法,但是也可能在使用者輸入、移動滑鼠、滾動螢幕或者點擊按鈕時調用該方法。它並不關心使用者在做什麼。
這就是稱之為非同步原因:使用者在一層上動作表單,而在另一層上伺服器響應請求並觸發 onreadystatechange
屬性指定的回調方法。