1. 程式人生 > >前端面試題——手寫實現 ajax

前端面試題——手寫實現 ajax

凡是和後臺有過資料互動的小夥伴肯定都接觸過 ajax. 我們可以通過 ajax 來實現頁面的無重新整理請求資料,這樣就能在保證良好使用者體驗的同時,將更多的內容展示給使用者
ajax 在我們的開發工作中已經司空見慣,幾乎所有我們頻繁使用的庫和框架都提供了經過完善封裝後的 ajax 方法,如 jQuery、zepto、angular 等等,這使得我們的資料請求變得異常簡潔明瞭

但是這也帶來了很明顯的缺陷,就是我們知道如何去使用封裝後的 ajax,卻不會通過原生的 js 來 ajax,更甚者(如只用過 jQuery 的小夥伴)會將 ajax 與$.ajax()等同

而這個問題也是面試中常常出現的一題,所以這次就來親手實現一下原生 js 的 ajax

XMLHttpRequest物件

我們常用的 ajax 就是通過 XMLHttpRequest 物件實現的,這個物件有很多的屬性和事件,在使用之前,我們需要先將它例項化

const xhr = new XMLHttpRequest()

例項化後,我們就可以通過 xhr 來發起一個請求

// xhr 具有一個 open 方法,這個方法的作用類似於初始化,並不會發起真正的請求
// open 方法具有 5 個引數,但是常用的是前 3 個
// method: 請求方式 —— get / post
// url:請求的地址
// async:是否非同步請求,預設為 true(非同步)
xhr.open(method, url, async)

// send 方法傳送請求,並接受一個可選引數
// 當請求方式為 post 時,可以將請求體的引數傳入
// 當請求方式為 get 時,可以不傳或傳入 null
// 不管是 get 還是 post,引數都需要通過 encodeURIComponent 編碼後拼接
xhr.send(data)


在通過send方法傳送請求後,xhr 物件在收到響應資料時會自動填充到其對應的屬性中,xhr 具有以下常用屬性:

responseText: 請求返回的資料內容
responseXML: 如果響應內容是"text/xml"“application/xml”,這個屬性將儲存響應資料的 XML DOM文件
status: 響應的HTTP狀態,如 200 304 404 等
statusText: HTTP狀態說明
readyStatus: 請求/響應過程的當前活動階段
timeout: 設定請求超時時間

上面寫了那麼多,我們並沒有發現收到資料時的回撥方法,那麼該怎麼在收到資料時進行處理呢?這個問題的重點需要放在readyStatus這個屬性上

readyStatus的值會隨著請求各階段的變化而改變,其一共有 5 個值:

xhr.readyStatus==0 尚未呼叫 open 方法
xhr.readyStatus==1 已呼叫 open 但還未傳送請求(未呼叫 send)
xhr.readyStatus==2 已傳送請求(已呼叫 send)
xhr.readyStatus==3 已接收到請求返回的資料
在通過send方法傳送請求後,xhr 物件在收到響應資料時會自動填充到其對應的屬性中,xhr 具有以下常用屬性:

responseText: 請求返回的資料內容
responseXML: 如果響應內容是"text/xml"“application/xml”,這個屬性將儲存響應資料的 XML DOM文件
status: 響應的HTTP狀態,如 200 304 404 等
statusText: HTTP狀態說明
readyStatus: 請求/響應過程的當前活動階段
timeout: 設定請求超時時間

上面寫了那麼多,我們並沒有發現收到資料時的回撥方法,那麼該怎麼在收到資料時進行處理呢?這個問題的重點需要放在readyStatus這個屬性上

xhr.readyStatus==0 尚未呼叫 open 方法
xhr.readyStatus==1 已呼叫 open 但還未傳送請求(未呼叫 send)
xhr.readyStatus==2 已傳送請求(已呼叫 send)
xhr.readyStatus==3 已接收到請求返回的資料
xhr.readyStatus==4 請求已完成

readyStatus的狀態發生改變時,會觸發 xhr 的事件onreadystatechange,於是我們就可以在這個方法中,對接收到的資料進行處理

xhr.onreadystatechange = () => {
    if (xhr.readyStatus === 4) {
        // HTTP 狀態在 200-300 之間表示請求成功
        // HTTP 狀態為 304 表示請求內容未發生改變,可直接從快取中讀取
        if (xhr.status >= 200 && 
            xhr.status < 300 || 
            xhr.status == 304) {
            console.log('請求成功', xhr.responseText)
        }
    }
}


當網路不佳時,我們需要給請求設定一個超時時間

// 超時時間單位為毫秒
xhr.timeout = 1000

// 當請求超時時,會觸發 ontimeout 方法
xhr.ontimeout = () => console.log(‘請求超時’)

以上就是 XMLHttpRequest 物件的基礎內容,它還有很多其他的屬性和時間,如onerror onabort onload等等,同時 ajax 的跨域、相容 IE 瀏覽器等問題我們也並沒有提到。對這些感興趣的小夥伴可以自己 Google 一下,或者等以後有機會,我們再一起來學習這些內容

下面奉上自己封裝的一個極簡 ajax 請求方法,在生產專案中不能使用,但是對於臨時測試請求個本地檔案什麼的還是沒什麼問題的,該 ajax 方法通過 Promise 方式實現回撥

function ajax (options) {
        let url = options.url
        const method = options.method.toLocaleLowerCase() || 'get'
        const async = options.async != false // default is true
        const data = options.data
        const xhr = new XMLHttpRequest()

        if (options.timeout && options.timeout > 0) {
            xhr.timeout = options.timeout
        }

        return new Promise ( (resolve, reject) => {
            xhr.ontimeout = () => reject && reject('請求超時')
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4) {
                    if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
                        resolve && resolve(xhr.responseText)
                    } else {
                        reject && reject()
                    }
                }
            }
            xhr.onerror = err => reject && reject(err)

            let paramArr = []
            let encodeData
            if (data instanceof Object) {
                for (let key in data) {
                    // 引數拼接需要通過 encodeURIComponent 進行編碼
                    paramArr.push( encodeURIComponent(key) + '=' + encodeURIComponent(data[key]) )
                }
                encodeData = paramArr.join('&')
            }

            if (method === 'get') {
                  // 檢測 url 中是否已存在 ? 及其位置
                const index = url.indexOf('?')
                if (index === -1) url += '?'
                else if (index !== url.length -1) url += '&'
                  // 拼接 url
                url += encodeData
            }

            xhr.open(method, url, async)
            if (method === 'get') xhr.send(null)
            else {
                // post 方式需要設定請求頭
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded;charset=UTF-8')
                xhr.send(encodeData)
            }
        } )


使用方式

ajax({
    url: 'your request url',
    method: 'get',
    async: true,
    timeout: 1000,
    data: {
        test: 1,
        aaa: 2
    }
}).then(
    res => console.log('請求成功: ' + res),
    err => console.log('請求失敗: ' + err)
)


如果你依然在程式設計的世界裡迷茫,不知道自己的未來規劃,可以加入web前端學習交流群:731771211

裡面可以與大神一起交流並走出迷茫。小白可進群免費領取學習資料,看看前輩們是如何在程式設計的世界裡傲然前行!群裡不停更新最新的教程和學習方法(進群送web前端系統學習路線,詳細的前端專案實戰教學視訊),有想學習web前端的,或是轉行,或是大學生,還有工作中想提升自己能力的,正在學習的小夥伴歡迎加入學習。

點選:加入

相關推薦

端面試題——實現 ajax

凡是和後臺有過資料互動的小夥伴肯定都接觸過 ajax. 我們可以通過 ajax 來實現頁面的無重新整理請求資料,這樣就能在保證良好使用者體驗的同時,將更多的內容展示給使用者 ajax 在我們的開發工作中已經司空見慣,幾乎所有我們頻繁使用的庫和框架都提供了經過完善

實現ajax實現過程及ajax跨域

1、手寫ajax的實現過程,不依賴任何第三方庫 主要考察XMLHttpRequest 物件,它用於在後臺與伺服器交換資料 版本ie使用ActiveXObject物件,該方法沒有做相容(根據目前行情,

端面試題二叉排序樹

前端面試題之手寫二叉排序樹 二叉排序樹:每個節點的左節點都比根節點小,右節點都比根節點大 function TreeNode(data, left, right) { //節點結構 this.val = data; this.left = left; this

ajax相關類web端面試題

1. ajax的跨域問題和快取原理?答:推薦:ajax處理跨域有幾種方式?實現原理是什麼?推薦:ajax快取原理2. 同步與非同步的區別?答: 1. 同步請求:順序處理,即當我們向伺服器發出一個請求時,在伺服器沒返回結果給客戶端之前,我們要一直處於等待狀態直至伺服器將結果返

端面試題系列2」如何實現一個聖盃佈局?

前言 最近,有個朋友向我訴苦說,面試的時候突然被問到了如何實現佈局和原理,有點懵。之前JavaScript的部分回答得挺好的,偏偏在這裡翻船了,完全沒有思路,後面的面試狀態一落千丈。結局也如他所料,沒有被錄取。 我給這個朋友做了解答之後,回家整理出此文。希望其他小夥伴面試中,再被問及聖盃佈局的時候,可以沉

好程式設計師web端面試題分享用線性漸變實現斜線

好程式設計師web前端面試題分享用線性漸變實現斜線 1、用線性漸變實現如下圖的斜線? 答案:<div><

JAVA面試題 ArrayList的實現,在筆試中過關斬將?

面試官Q1:可以手寫一個ArrayList的簡單實現嗎? 我們都知道ArrayList是基於陣列實現,如果讓你實現JDK原始碼ArrayList中add()、remove()、get()方法,你知道如何實現嗎?這一節,我們不看原始碼,我們想想如何簡單的實現ArrayList幾個基本方法?  

端面試題(來自前端網http://www.qdfuns.com/notes/23515/c9163ddd620baac5dd23141d41982bb8.html)

設置 session hat eval 減少 還需要 height 狀態碼 一次 HTML&CSS 1. 常用那幾種瀏覽器測試?有哪些內核(Layout Engine)? (Q1)瀏覽器:IE,Chrome,FireFox,Safari,Opera。 (Q2)內核

端面試題二(來自前端網http://www.qdfuns.com/notes/23515/fa8b1e788ac39b04108fc33e5b543c4a.html)

scrip border cal 搜索引擎 val 媒體 分配 error 不刷新 HTML&CSS 1.請描述一下 cookies,sessionStorage 和 localStorage 的區別? cookie是網站為了標示用戶身份而儲存在用戶本地終端(Cl

js操作符類型轉換大全(端面試題之操作符)

ber 出錯 mas java http pos ted 一個數 類型轉換 操作符運算符,在前端的面試題目中經常出現,很多朋友在對其運算的時候經常出錯。說明對操作符運算還沒有完全理解,我前面的一篇文章,javascript雙等號引起的類型轉換,主要講解雙等號引起的類型轉換。

web端面試題

案例 asc eva nbsp != radi XML vertica 意義 面試有幾點需註意 面試題目: 根據你的等級和職位變化,入門級到專家級:範圍↑、深度↑、方向↑。 題目類型: 技術視野、項目細節、理論知識題,算法題,開放性題,案例題。 進行追問:

web端面試題系列:(二)

html name 價值 編程 oct rom repeat 清除 frame 1、列舉你工作中遇到的IE6 BUG,談談解決方案 a.雙倍邊距bug: 例如:當給父元素內第一個浮動元素設置margin-left或margin-right的時候,margin屬性會加倍,

最近面試端面試題整理(css部分)

type list 定位 text -c padding 面試 lang vertical 對最近面試的面試題坐下總結: 一,css部分 1,html元素的垂直居中 答案: <div id="box"> <div> 測

2017端面試題之Css篇(1)

margin 沒有 width ati clas 經驗 visible import tom 1 . CSS 屬性是否區分大小寫? 答:不區分。 HTML,CSS都對大小寫不敏感,但為了更好的可讀性和團隊協作一般都小寫,而在XHTML 中元素名稱和屬性是必須小寫的。

2017端面試題之Html篇(1)

utf doctype clas 停止 要求 驅動 抓取 -c 顯示錯誤 1 . doctype(文檔類型) 的作用是什麽? 對文檔進行有效性驗證: 它告訴用戶代理和校驗器這個文檔是按照什麽DTD 寫的。這個動作是被動的, 每次頁面加載時,瀏覽器並不會下載DTD

2017端面試題之Js篇(1)

load urn lis property eat hub bind tlist 方法的參數 1 . 請解釋事件代理 (event delegation) 當需要對很多元素添加事件的時,可以通過將事件添加到它們的父節點通過委托來觸發處理函數。其中利用到了瀏覽器的事件冒

web端面試題整理(HTML篇)

pad 關閉 選擇 words vid onunload adding per end 1. h5的改進: 新元素畫布canvas: HTML5 <canvas>元素用於圖形的繪制,通過腳本 (通常是JavaScript)來完成音頻audio視頻vid

透徹理解Spring事務設計思想之實現

數據庫操作 cal 了解 hashmap 個數 這一 use action 管道 前言 事務,是描述一組操作的抽象,比如對數據庫的一組操作,要麽全部成功,要麽全部失敗。事務具有4個特性:Atomicity(原子性),Consistency(一致性),Isolation(隔離

理解數據庫連接池底層原理之實現

ring cda color 要去 分配 .com 管理 roc tex 前言 數據庫連接池的基本思想是:為數據庫連接建立一個“緩沖池”,預先在池中放入一定數量的數據庫連接管道,需要時,從池子中取出管道進行使用,操作完畢後,在將管道放入池子中,從而避免了頻繁的向數據庫申請資

端面試題 ----css篇

設定 nbu radi tab 根據 pointer position net 放置 1、css盒模型有哪些及區別content-box border-box padding-box IE盒子模型box-sizing:border-box;(怪異模式) W3C標準盒子模