欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS實(shí)現(xiàn)網(wǎng)絡(luò)請求的三種方式梳理

 更新時(shí)間:2022年03月03日 09:24:02   作者:有道技術(shù)團(tuán)隊(duì)  
本文主要為大家介紹了基于 XMLHttpRequest、Promise、async/await 等三種異步網(wǎng)絡(luò)請求的寫法,文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下

背景

為了應(yīng)對越來越多的測試需求,減少重復(fù)性的工作,有道智能硬件測試組基于 electron 開發(fā)了一系列測試提效工具。

隨著工具的快速開發(fā)迭代,代碼中出現(xiàn)了越來越多的嵌套的回調(diào)函數(shù),工具崩潰的幾率也越來越大。為了解決這些問題, 我們用 async/await 對這些回調(diào)函數(shù)進(jìn)行了重構(gòu), 使得代碼量下降,代碼的可讀性和可理解性都有了大幅度提高。

本文介紹了 基于 XMLHttpRequest、Promise、async/await 等三種異步網(wǎng)絡(luò)請求 的寫法,其中 async/await 寫法允許我們以類似于同步的方式編寫異步程序,擺脫繁瑣的回調(diào)函數(shù)。

前言

在 js 中如果只是發(fā)起單個(gè)網(wǎng)絡(luò)請求還不算復(fù)雜,用fetch、axios或者直接用XMLHttpRequest就能滿足要求。

但若是多個(gè)請求按順序拉取數(shù)據(jù)那寫起來就很麻煩了,因?yàn)?js 中的網(wǎng)絡(luò)請求都是異步的,想要順序執(zhí)行, 最常見寫法就是在回調(diào)函數(shù)中發(fā)起下一個(gè)請求 ,如下面這些代碼:

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));

假設(shè)我需要經(jīng)過兩步獲取一個(gè)數(shù)據(jù),如從 https://xxx.yyy.com/api/zzz/ 獲取一個(gè)數(shù)據(jù)對象data,通過 data.id 得到我要獲取數(shù)據(jù)的序號(hào),之后再發(fā)一次請求得到想要的數(shù)據(jù)。

用回調(diào)函數(shù)的方式就類似于上面這樣,太繁瑣了,而且容易出錯(cuò),并且一旦邏輯復(fù)雜就不好改。

接下來梳理一下js的幾種網(wǎng)絡(luò)請求方式,擺脫回調(diào)地獄,希望對遇到類似問題的小伙伴有所幫助。

XMLHttpRequest

首先是 XMLHttpRequest,初學(xué)前端時(shí)大名鼎鼎的 Ajax 主要指的就是它。通過 XMLHttpRequest 對象創(chuàng)建網(wǎng)絡(luò)請求的套路如下:

// 假設(shè)訪問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()

這段代碼首先創(chuàng)建一個(gè) XMLHttpRequest 對象 xhr,然后給 xhr.onreadystatechange 添加 readystatechange 事件的回調(diào)函數(shù),之后 xhr.open('GET',url) 初始化請求,最后由xhr.send() 發(fā)送請求。

請求發(fā)送后,程序會(huì)繼續(xù)執(zhí)行不會(huì)阻塞,這也是異步調(diào)用的好處。當(dāng)瀏覽器收到響應(yīng)時(shí)就會(huì)進(jìn)入xhr.onreadystatechange 的回調(diào)函數(shù)中去。在整個(gè)請求過程中, xhr.onreadystatechange會(huì)觸發(fā)四次,每次 readyState 都會(huì)自增,從1一直到4,只有到了最后階段也就是readyState為4時(shí)才能得到最終的響應(yīng)數(shù)據(jù)。

到達(dá)第四階段后還要根據(jù) status 判斷響應(yīng)的狀態(tài)碼是否正常,通常響應(yīng)碼為200說明請求沒有遇到問題。這段代碼最終會(huì)在控制臺(tái)上會(huì)打出 YouDao。

可以看出,通過XMLHttpRequest處理請求的話,首先要針對每個(gè)請求創(chuàng)建一個(gè) XMLHttpRequest 對象,然后還要對每個(gè)對象綁定 readystatechange 事件的回調(diào)函數(shù),若是多個(gè)請求串起來,想想就很麻煩。

Promise

Promise 是在 ECMAScript 2015 引入的,如果一個(gè)事件依賴于另一個(gè)事件返回的結(jié)果,那么使用回調(diào)會(huì)使代碼變得很復(fù)雜。

Promise 對象提供了檢查操作失敗或成功的一種模式。如果成功,則會(huì)返回另一個(gè)Promise。這使得回調(diào)的書寫更加規(guī)范。

通過 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"))

上面這段代碼把整個(gè)處理過程串起來了,首先創(chuàng)建一個(gè) Promise 對象,它的構(gòu)造器接收一個(gè)函數(shù),函數(shù)的第一個(gè)參數(shù)是沒出錯(cuò)時(shí)要執(zhí)行的函數(shù) resolve,第二個(gè)參數(shù)是出錯(cuò)后要執(zhí)行的函數(shù)r eject。

resolve 指執(zhí)行成功后then里面的回調(diào)函數(shù),reject 指執(zhí)行失敗后catch里執(zhí)行的回調(diào)函數(shù)。最后的 finally 是不論成功失敗都會(huì)執(zhí)行的,可以用來做一些收尾清理工作。

基于 Promise 的網(wǎng)絡(luò)請求可以用 axios 庫或?yàn)g覽器自帶的 fetch 實(shí)現(xiàn)。

axios 庫創(chuàng)建請求的套路如下:

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,它不需要導(dǎo)庫,fetch 創(chuàng)建請求的方式和axios類似,在開頭已經(jīng)展示過了就不重復(fù)寫了。

雖然 Promise 把回調(diào)函數(shù)的編寫方式簡化了一些,但還是沒有擺脫回調(diào)地獄,多個(gè)請求串起來的話就會(huì)像我開頭寫的那樣,在 then 里面創(chuàng)建新的 Promise,最終變成 Promise 地獄。

async/await

async/await 是在 ECMAScript 2017 引入的,可以簡化 Promise 的寫法,使得代碼中的異步函數(shù)調(diào)用可以按順序執(zhí)行,易于理解。

下面就用開頭的那個(gè)例子說明吧:

直接用 fetch 獲取數(shù)據(jù):

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 跟在后面了,這樣如果有一連串的網(wǎng)絡(luò)請求也不用怕了。

當(dāng) async 放在一個(gè)函數(shù)的聲明前時(shí),這個(gè)函數(shù)就是一個(gè)異步函數(shù),調(diào)用該函數(shù)會(huì)返回一個(gè)Promise。

await 用于等待一個(gè) Promise 對象,它只能在異步函數(shù)中使用,await 表達(dá)式會(huì)暫停當(dāng)前異步函數(shù)的執(zhí)行,等待 Promise 處理完成。

這樣如果想讓一連串的異步函數(shù)調(diào)用順序執(zhí)行,只要把被調(diào)用的這些函數(shù)放到一個(gè)用async修飾的函數(shù)中,調(diào)用前加上 await 就能讓這些函數(shù)乖乖地順序執(zhí)行了。

結(jié)語

通過本文的梳理,相信你已經(jīng)知道怎樣避免回調(diào)地獄了。不過需要注意的是 Promise 是2015年加入語言規(guī)范的,而 async/await 是2017年才加入到語言規(guī)范的,如果你的項(xiàng)目比較老或者是必須要兼容老版本的瀏覽器(如IE6),那就需要用別的方式來解決回調(diào)地獄了。

對于 electron 只要你用的是近幾年的版本都是支持的,electron 可以當(dāng)成是 chromium 和 node.js 的結(jié)合體,特別適合用來寫跨平臺(tái)的工具類桌面應(yīng)用程序。

到此這篇關(guān)于JS實(shí)現(xiàn)網(wǎng)絡(luò)請求的三種方式梳理的文章就介紹到這了,更多相關(guān)JS網(wǎng)絡(luò)請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論