這篇文章將為大家詳細講解有關JS實現網絡請求的方式有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
為了應對越來越多的測試需求,減少重復性的工作,有道智能硬件測試組基于 electron 開發了一系列測試提效工具。
隨著工具的快速開發迭代,代碼中出現了越來越多的嵌套的回調函數,工具崩潰的幾率也越來越大。為了解決這些問題, 我們用 async/await 對這些回調函數進行了重構, 使得代碼量下降,代碼的可讀性和可理解性都有了大幅度提高。
本文介紹了 基于 XMLHttpRequest、Promise、async/await 等三種異步網絡請求 的寫法,其中 async/await 寫法允許我們以類似于同步的方式編寫異步程序,擺脫繁瑣的回調函數。
在 js 中如果只是發起單個網絡請求還不算復雜,用fetch、axios或者直接用XMLHttpRequest就能滿足要求。
但若是多個請求按順序拉取數據那寫起來就很麻煩了,因為 js 中的網絡請求都是異步的,想要順序執行, 最常見寫法就是在回調函數中發起下一個請求 ,如下面這些代碼:
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch('https://xxx.yyy.com/api/zzz/', requestOptions)
.then(response => response.json())
.then(data => {
fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
.then(response => response.json())
.then(data => {
console.log(data)
})
.catch(error => console.error('error', error));
})
.catch(error => console.error('error', error));假設我需要經過兩步獲取一個數據,如從 https://xxx.yyy.com/api/zzz/ 獲取一個數據對象data,通過 data.id 得到我要獲取數據的序號,之后再發一次請求得到想要的數據。
用回調函數的方式就類似于上面這樣,太繁瑣了,而且容易出錯,并且一旦邏輯復雜就不好改。
接下來梳理一下js的幾種網絡請求方式,擺脫回調地獄,希望對遇到類似問題的小伙伴有所幫助。
首先是 XMLHttpRequest,初學前端時大名鼎鼎的 Ajax 主要指的就是它。通過 XMLHttpRequest 對象創建網絡請求的套路如下:
// 假設訪問http://localhost:3000/user返回json對象{"name":"YouDao"}
const xhr = new XMLHttpRequest();
const url = 'http://localhost:3000/user'
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
const json=JSON.parse(xhr.responseText)
const name=json.name
console.log(name)
}
}
xhr.open('GET',url)
xhr.send()這段代碼首先創建一個 XMLHttpRequest 對象 xhr,然后給 xhr.onreadystatechange 添加 readystatechange 事件的回調函數,之后 xhr.open('GET',url) 初始化請求,最后由xhr.send() 發送請求。
請求發送后,程序會繼續執行不會阻塞,這也是異步調用的好處。當瀏覽器收到響應時就會進入xhr.onreadystatechange 的回調函數中去。在整個請求過程中, xhr.onreadystatechange會觸發四次,每次 readyState 都會自增,從1一直到4,只有到了最后階段也就是readyState為4時才能得到最終的響應數據。
到達第四階段后還要根據 status 判斷響應的狀態碼是否正常,通常響應碼為200說明請求沒有遇到問題。這段代碼最終會在控制臺上會打出 YouDao。
可以看出,通過XMLHttpRequest處理請求的話,首先要針對每個請求創建一個 XMLHttpRequest 對象,然后還要對每個對象綁定 readystatechange 事件的回調函數,若是多個請求串起來,想想就很麻煩。
Promise 是在 ECMAScript 2015 引入的,如果一個事件依賴于另一個事件返回的結果,那么使用回調會使代碼變得很復雜。
Promise 對象提供了檢查操作失敗或成功的一種模式。如果成功,則會返回另一個Promise。這使得回調的書寫更加規范。
通過 Promise 處理的套路如下:
const promise = new Promise((resolve,reject)=>{
let condition = true;
if (condition) {
resolve("ok")
} else {
reject("failed")
}
}).then( msg => console.log(msg))
.catch( err => console.error(err))
.finally( _ =>console.log("finally"))上面這段代碼把整個處理過程串起來了,首先創建一個 Promise 對象,它的構造器接收一個函數,函數的第一個參數是沒出錯時要執行的函數 resolve,第二個參數是出錯后要執行的函數r eject。
resolve 指執行成功后then里面的回調函數,reject 指執行失敗后catch里執行的回調函數。最后的 finally 是不論成功失敗都會執行的,可以用來做一些收尾清理工作。
基于 Promise 的網絡請求可以用 axios 庫或瀏覽器自帶的 fetch 實現。
axios 庫創建請求的套路如下:
import axios from 'axios' const url = 'http://xxx.yyy.com/' axios.get(url) .then(data => console.log(data)) .catch(err => console.error(err))
我比較喜歡用 fetch,fetch 是用來代替 XMLHttpRequest 的瀏覽器 API,它不需要導庫,fetch 創建請求的方式和axios類似,在開頭已經展示過了就不重復寫了。
雖然 Promise 把回調函數的編寫方式簡化了一些,但還是沒有擺脫回調地獄,多個請求串起來的話就會像我開頭寫的那樣,在 then 里面創建新的 Promise,最終變成 Promise 地獄。
async/await 是在 ECMAScript 2017 引入的,可以簡化 Promise 的寫法,使得代碼中的異步函數調用可以按順序執行,易于理解。
下面就用開頭的那個例子說明吧:
直接用 fetch 獲取數據:
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch('https://xxx.yyy.com/api/zzz/', requestOptions)
.then(response => response.json())
.then(data => {
fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
.then(response => response.json())
.then(data => {
console.log(data)
})
.catch(error => console.error('error', error));
})
.catch(error => console.error('error', error));用async/await改寫后:
async function demo() {
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
const response = await fetch('https://xxx.yyy.com/api/zzz/', requestOptions);
const data = await response.json()
const response1 = await fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
const data1 = await response1.json()
console.log(data1)
}
demo().catch(error => console.error('error',error))改寫后的代碼是不是就很清楚了,沒有那么多的 then 跟在后面了,這樣如果有一連串的網絡請求也不用怕了。
當 async 放在一個函數的聲明前時,這個函數就是一個異步函數,調用該函數會返回一個Promise。
await 用于等待一個 Promise 對象,它只能在異步函數中使用,await 表達式會暫停當前異步函數的執行,等待 Promise 處理完成。
這樣如果想讓一連串的異步函數調用順序執行,只要把被調用的這些函數放到一個用async修飾的函數中,調用前加上 await 就能讓這些函數乖乖地順序執行了。
關于“JS實現網絡請求的方式有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。