69pao国产精品视频-久久精品一区二区二三区-精品国产精品亚洲一本大道-99国产综合一区久久

一文掌握ajax、fetch和axios的區(qū)別對比
目錄

ajax、fetch、axios

ajax

ajax可以在不更新全局的情況下更新局部頁面。通過在與服務(wù)器進(jìn)行數(shù)據(jù)交換,可以使網(wǎng)頁實現(xiàn)異步更新。

ajax的原理就是通過xhr對象來向服務(wù)器發(fā)起異步請求,從服務(wù)器獲得數(shù)據(jù),然后用js來操作dom更新頁面。領(lǐng)導(dǎo)想找小李匯報一下工作,就委托秘書去叫小李,自己就接著做其他事情,直到秘書告訴他小李已經(jīng)到了,最后小李跟領(lǐng)導(dǎo)匯報工作。ajax請求數(shù)據(jù)流程與“領(lǐng)導(dǎo)想找小李匯報一下工作”類似,上述秘書就相當(dāng)于xmlhttprequest對象,領(lǐng)導(dǎo)相當(dāng)于瀏覽器,響應(yīng)數(shù)據(jù)相當(dāng)于小李。瀏覽器可以發(fā)送http請求后,接著做其他事情,等收到xhr返回來的數(shù)據(jù)再進(jìn)行操作。

image

創(chuàng)建ajax

// 1. 創(chuàng)建 xmlhttprequest 實例
let xhr = xmlhttprequest()
// 2. 打開和服務(wù)器的連接
xhr.open('get', 'url')
// 3.發(fā)送
xhr.send()
// 4. 接收變化。
xhr.onreadystatechange = () => {
    if(xhr.readystate == 4 && xhr.status == 200){   // readystate: ajax 狀態(tài),status:http 請求狀態(tài)
        console.log(xhr.responsetext);   //響應(yīng)主體
    }
}
  • 創(chuàng)建ajax實例:let xhr = new xmlhttprequest()
  • 打開請求,配置請求前的配置項:xhr.open([http method], [url], [async], [username], [userpass])
  • http methods 請求方式:post,get,delete,put,head,options,trace,connect
  • url:想服務(wù)器請求的路徑
  • async:是否為異步請求
  • username、userpass:用戶名與密碼
    • 通過xmlhttprequest.open()方法與服務(wù)器建立連接
    • 發(fā)送請求:xmlhttprequest.send() 方法中如果 ajax 請求是異步的則這個方法發(fā)送請求后就會返回,如果ajax請求是同步的,那么請求必須知道響應(yīng)后才會返回。
    • 通過xmlhttprequest對象的onreadystatechange事件監(jiān)聽服務(wù)器端的通信狀態(tài)
    • 接收數(shù)據(jù)并進(jìn)行處理
    • 將處理后的結(jié)果更新到頁面上

    ajax的缺點(diǎn):

    • 本是針對mvc架構(gòu),不符合前端mvvm的浪潮
    • 基于原生的xhr開發(fā)
    • 配置和調(diào)用方式混亂

    axios原理

    axios是使用promise封裝的ajax,它內(nèi)部有兩個攔截器,分別是request攔截器和response攔截器。

    • 請求攔截器的作用是在請求發(fā)送之前進(jìn)行一些操作,例如在每個請求體上加入token
    • 響應(yīng)攔截器的作用是接收到響應(yīng)后做的一些操作,例如登錄失效后需要重新登錄跳轉(zhuǎn)到登錄頁

    axios的特點(diǎn)

    • 由瀏覽器端發(fā)起請求,在瀏覽器中創(chuàng)建xhr
    • 支持promise api
    • 監(jiān)聽請求和返回
    • 更好的格式化,自動將數(shù)據(jù)轉(zhuǎn)換為json數(shù)據(jù)
    • 安全性更高,可抵御csrf攻擊

    axios常用的方法

    axios常用的方法有get、post、put、patch、delete等。其中getpost返回的都是promise對象,可以使用promise方法

    axios.get(url[, config]):get請求用于列表和信息查詢

    axios.get('apiurl', {
        param: {
            id: 1
        }
        // param 中的的鍵值對最終會 ? 的形式,拼接到請求的鏈接上,發(fā)送到服務(wù)器。
    }).then(res => {
        console.log(res);
    })
    .catch( error => {
        console.log(error)
    }

    axios.delete(url[, config]):刪除

    axios.delete('apiurl', {
        params: {
            id: 1
        },
        timeout: 1000
    })

    axios.post(url[, data[, config]]):post請求用于信息的添加

    axios.post('apiurl',{
            user: '小新',
            age: 18
    }).then( res => {
        console.log(res);
    })
    .catch( error => {
        console.log(error)
    }
    

    axios.put(url[, data[, config]]):更新操作

    axios.put('apiurl', {
        name: '小新',
    })
    

    axios.patch(url[, data[, config]]):更新操作

    axios.patch('apiurl', {
        id: 13,
    },{
       timeout: 1000,
    })
    

    put和patch的區(qū)別

    patch方法用來更新局部資源,假設(shè)我們有一個userinfo,里面有userid,username,usergender等10個字段。可你的編輯功能因為需求,在某個特別的頁面里只能修改username,這個時候就可以使用patch。

    put也適用于更新數(shù)據(jù),但必須提供完整的資源對象。

    axios相關(guān)配置

    • url:用于請求服務(wù)器的url
    • method:請求方法,默認(rèn)為get
    • baseurl:會自動加到url前面
    • proxy:用于配置代理
    • transformrequest:允許在服務(wù)器發(fā)送請求之前修改請求數(shù)據(jù)

    axios攔截器執(zhí)行順序問題

    • 請求攔截:axios的請求攔截器會先執(zhí)行最后指定的回調(diào)函數(shù),再依次向前執(zhí)行
    • 響應(yīng)攔截:axios的響應(yīng)攔截器會先執(zhí)行最先執(zhí)行的回調(diào)函數(shù),再依次向前執(zhí)行

    例如:

    axios.interceptors.request.use(config => {
      console.log(`請求攔截1`);
      return config;
    });
    axios.interceptors.request.use(config => {
      // 在發(fā)送請求之前做些什么 
      console.log(`請求攔截2`);
      return config;
    });
    
    // 添加響應(yīng)攔截器 
    axios.interceptors.response.use(response => {
      // 對響應(yīng)數(shù)據(jù)做點(diǎn)什么 
      console.log(`成功的響應(yīng)攔截1`);
      return response.data;
    });
    
    // 添加響應(yīng)攔截器 
    axios.interceptors.response.use(response => {
      // 對響應(yīng)數(shù)據(jù)做點(diǎn)什么 
      console.log(`成功的響應(yīng)攔截2`);
      return response;
    });
    
    // 發(fā)送請求 
    axios.get('/posts')
      .then(response => {
        console.log('成功了');
      }) 
    

    執(zhí)行結(jié)果為

    console.log("請求攔截2");
    console.log("請求攔截1");
    console.log("成功的響應(yīng)攔截1");
    console.log("成功的響應(yīng)攔截2");
    console.log("成功了");

    為什么axios中需要攔截器

    在spa應(yīng)用中,通常會使用token進(jìn)行用戶身份認(rèn)證,這就要求每次請求必須攜帶用戶的身份信息,針對這個需求,為了避免在每個請求中單獨(dú)處理,我們可以通過封裝統(tǒng)一的request函數(shù)來為每隔請求統(tǒng)一添加token信息。

    但如果想為某些請求添加緩存時間或者控制某些請求的調(diào)用頻率的話,我們就需要不斷地修改request函數(shù)來擴(kuò)展對應(yīng)的功能。此時,如果在考慮對響應(yīng)進(jìn)行統(tǒng)一處理,我們的request函數(shù)將變得越來越龐大,也越來越難維護(hù)。所以axios為我們提供了攔截器。

    為什么請求攔截2會在請求攔截1之前執(zhí)行呢?

    axios源碼中將發(fā)送請求分為了請求攔截器、發(fā)送請求、響應(yīng)攔截器、相應(yīng)回調(diào),通過promise的鏈?zhǔn)秸{(diào)用將這些部分結(jié)合起來了,這樣就得到了發(fā)送請求拿到數(shù)據(jù)的全部過程。

    下面分析源碼:

    • 代碼開始構(gòu)建了一個config配置對象,用于第一次執(zhí)行promise返回一個成功的promise
    • 最核心的數(shù)組chain,這個數(shù)組中保存了請求攔截器、響應(yīng)攔截器和發(fā)送請求函數(shù)。該數(shù)組中間放的是發(fā)送請求的函數(shù),左邊放的是請求攔截器,右邊放的是響應(yīng)攔截器。在第一步中返回的promise對象,將遍歷chain數(shù)組逐一執(zhí)行里面的函數(shù),并返回新的promise對象
    • 往數(shù)組中添加請求攔截函數(shù),依照axios請求的執(zhí)行順序,請求攔截器應(yīng)該在發(fā)送請求之前執(zhí)行,故應(yīng)該添加在發(fā)送請求函數(shù)的前面,使用unshift方法
    • 往數(shù)組中添加響應(yīng)攔截器函數(shù),依照axios請求的執(zhí)行順序,響應(yīng)攔截器應(yīng)該在發(fā)送請求之后執(zhí)行,故應(yīng)該添加在發(fā)送請求函數(shù)的后面,所以使用的是數(shù)組的push方法
    • promise遍歷執(zhí)行,每次從chain中取出兩個 函數(shù)執(zhí)行(一個成功回調(diào),一個失敗回調(diào))
    • 最后返回一個promise對象,用于執(zhí)行響應(yīng)數(shù)據(jù)的回調(diào)

    image

    fetch
    fetch是http請求數(shù)據(jù)的方式,它使用promise,但不使用回調(diào)函數(shù)。fetch采用模塊化設(shè)計,通過數(shù)據(jù)流處理數(shù)據(jù),對于請求大文件或網(wǎng)速慢的情況相當(dāng)有用。默認(rèn)情況下fetch不會接收或發(fā)送cookies。

    優(yōu)點(diǎn):

    • 采用模塊化思想,將輸入、輸出、狀態(tài)跟蹤分離
    • 基于promise,返回一個promise對象

    缺點(diǎn):

    • 過于底層,有很多狀態(tài)碼沒有進(jìn)行封裝
    • 無法阻斷請求
    • 兼容性差無法檢測請求進(jìn)度

    fetch、ajax與axios的區(qū)別

    • 傳統(tǒng)的ajax利用的是hmlhttprequest這個對象,和后端進(jìn)行交互。
    • jqury ajax是對原生xhr的封裝,多請求間有嵌套的話就會出現(xiàn)回調(diào)地獄的問題。
    • axios使用promise封裝xhr,解決了回調(diào)地獄的問題。而fetch沒有使用xhr,使用的是promise

    fetch和ajax比有什么優(yōu)點(diǎn)

    fetch使用的是promise,方便使用異步,沒有回調(diào)地獄的問題。

    總結(jié)

    image

    ajax是一種web數(shù)據(jù)交互的方式,它可以使頁面在不重新加載的情況下請求數(shù)據(jù)并進(jìn)行局部更新,它內(nèi)部使用了xhr來進(jìn)行異步請求。ajax在使用xhr發(fā)起異步請求時得到的是xml格式的數(shù)據(jù),如果想要json格式,需要進(jìn)行額外的轉(zhuǎn)換;ajax本身針對的是mvc框架,不符合現(xiàn)在的mvvm架構(gòu);ajax有回調(diào)地獄問題;ajax的配置復(fù)雜

    fetch是xhr的代替品,它基于promise實現(xiàn)的,并且不使用回調(diào)函數(shù),它采用模塊化結(jié)構(gòu)設(shè)計,并使用數(shù)據(jù)流進(jìn)行傳輸,對于大文件和網(wǎng)速慢的情況非常友好。但是fetch不會對請求和響應(yīng)進(jìn)行監(jiān)聽;不能阻斷請求;過于底層,對一些狀態(tài)碼沒有封裝;兼容性差。

    axios是基于promisexhr進(jìn)行封裝,它內(nèi)部封裝了兩個攔截器,分別是請求攔截器和響應(yīng)攔截器。請求攔截器用于在請求發(fā)出之前進(jìn)行一些操作,比如:設(shè)置請求體,攜帶cookie、token等;響應(yīng)攔截器用于在得到響應(yīng)后進(jìn)行一些操作,比如:登錄失效后跳轉(zhuǎn)到登錄頁面重新登錄。axios有g(shù)et、post、put、patch、delete等方法。axios可以對請求和響應(yīng)進(jìn)行監(jiān)聽;返回promise對象,可以使用promise的api;返回json格式的數(shù)據(jù);由瀏覽器發(fā)起請求;安全性更高,可以抵御csrf攻擊。

    axios源碼分析

    axios的執(zhí)行流程

    • 使用axios.create創(chuàng)建單獨(dú)的實例,或直接使用axios實例
    • 對于axios調(diào)用進(jìn)入到request()中進(jìn)行處理
    • 執(zhí)行請求攔截器
    • 請求數(shù)據(jù)轉(zhuǎn)換器,將傳入的數(shù)據(jù)進(jìn)行處理,比如json.stringify(data)
    • 執(zhí)行適配器,判斷是瀏覽器端還是node端,以執(zhí)行不同的方法
    • 響應(yīng)數(shù)據(jù)轉(zhuǎn)換器,對服務(wù)器端的數(shù)據(jù)進(jìn)行處理,比如json.parse(data)
    • 執(zhí)行響應(yīng)攔截器,對服務(wù)器端數(shù)據(jù)進(jìn)行處理,比如token失效跳轉(zhuǎn)到登錄頁
    • 返回數(shù)據(jù)

    image

    入口文件(lib/axios.js)

    導(dǎo)出的axios就是 實例化后的對象,還在其上掛載create方法,以供創(chuàng)建獨(dú)立的實例,實現(xiàn)實例之間互不影響。

    // 創(chuàng)建實例過程的方法
    function createinstance(defaultconfig) {
      return instance;
    }
    // 實例化
    var axios = createinstance(defaults);
     
    // 創(chuàng)建獨(dú)立的實例,隔離作用域
    axios.create = function create(instanceconfig) {
      return createinstance(mergeconfig(axios.defaults, instanceconfig));
    };
    // 導(dǎo)出實例
    module.exports = axios;
    

    createinstance()

    function createinstance(defaultconfig) {
      // 實例化,創(chuàng)建一個上下文
      var context = new axios(defaultconfig);
     
      // 平時調(diào)用的 get/post 等等請求,底層都是調(diào)用 request 方法
      // 將 request 方法的 this 指向 context(上下文),形成新的實例
      var instance = bind(axios.prototype.request, context);
     
      // axios.prototype 上的方法 (get/post...)掛載到新的實例 instance 上,
      // 并且將原型方法中 this 指向 context
      utils.extend(instance, axios.prototype, context);
     
      // axios 屬性值掛載到新的實例 instance 上
      // 開發(fā)中才能使用 axios.default/interceptors
      utils.extend(instance, context);
     
      return instance;
    }
    

    createinstance執(zhí)行流程:

    • 通過構(gòu)造函數(shù)axios創(chuàng)建實例context,作為下面request方法的上下文(this指向)
    • axios.prototype.request方法作為實例使用,并把this指向context,形成新的實例instance
    • 將構(gòu)造函數(shù)axios.prototype上的方法掛載到新的實例instance上,然后將原型各個方法中的this指向context,這樣才能使用get、post等方法
    • axios的屬性掛載到instance

    可以看到axios不是簡單的創(chuàng)建實例context,而是在context上進(jìn)行this綁定形成新的實例,然后將axios屬性和請求方法掛載到新的實例上

    攔截器(lib/core/interceptormanager.js)

    攔截器涉及一個屬性和三個方法:

    • handler:存放use注冊的回調(diào)函數(shù)
    • use:注冊成功和失敗的回調(diào)函數(shù)
    • eject:刪除注冊過的函數(shù)
    • foreach:遍歷回調(diào)函數(shù)
    function interceptormanager() {
      // 存放 use 注冊的回調(diào)函數(shù)
      this.handlers = [];
    }
    
    interceptormanager.prototype.use = function use(fulfilled, rejected, options) {
      // 注冊成功和失敗的回調(diào)函數(shù)
      this.handlers.push({
        fulfilled: fulfilled,
        rejected: rejected,
        ...
      });
      return this.handlers.length - 1;
    };
    
    interceptormanager.prototype.eject = function eject(id) {
      // 刪除注冊過的函數(shù)
      if (this.handlers[id]) {
        this.handlers[id] = null;
      }
    };
    
    interceptormanager.prototype.foreach = function foreach(fn) {
      // 遍歷回調(diào)函數(shù),一般內(nèi)部使用多
      utils.foreach(this.handlers, function foreachhandler(h) {
        if (h !== null) {
          fn(h);
        }
      });
    };
    

    dispatchrequest(lib/core/dispatchrequest.js)

    dispatchrequest主要做了以下操作:

    • transformrequest: 對 config 中的 data 進(jìn)行加工,比如對 post 請求的 data 進(jìn)行字符串化(json.stringify(data))
    • adapter:適配器,包含瀏覽器端 xhr 和 node 端的 http
    • transformresponse: 對服務(wù)端響應(yīng)的數(shù)據(jù)進(jìn)行加工,比如 json.parse(data)

    image

    取消請求(lib/cancel/canceltoken.js)

    var canceltoken = axios.canceltoken;
    var source = canceltoken.source();
    axios.get('/user/12345', {
      canceltoken: source.token
    }).catch(function(thrown) {
      if (axios.iscancel(thrown)) {
        console.log('request canceled', thrown.message);
      } else {
        // 處理錯誤
      }
    });
    // 取消請求(message 參數(shù)是可選的)
    source.cancel('operation canceled by the user.');
    
    • canceltoken 掛載 source 方法用于創(chuàng)建自身實例,并且返回 {token, cancel}
    • token 是構(gòu)造函數(shù) canceltoken 的實例,cancel 方法接收構(gòu)造函數(shù) canceltoken 內(nèi)部的一個 cancel 函數(shù),用于取消請求
    • 創(chuàng)建實例中,有一步是創(chuàng)建處于 pengding 狀態(tài)的 promise,并掛在實例方法上,外部通過參數(shù) canceltoken 將實例傳遞進(jìn) axios 內(nèi)部,內(nèi)部調(diào)用 canceltoken.promise.then 等待狀態(tài)改變
    • 當(dāng)外部調(diào)用方法 cancel 取消請求,pendding 狀態(tài)就變?yōu)?resolve,即取消請求并且拋出 reject(message)

    總結(jié)

    • 為了支持 axios() 簡潔寫法,內(nèi)部使用 request 函數(shù)作為新實例
    • 使用 promsie 鏈?zhǔn)秸{(diào)用的巧妙方法,解決順序調(diào)用問題
    • 數(shù)據(jù)轉(zhuǎn)換器方法使用數(shù)組存放,支持?jǐn)?shù)據(jù)的多次傳輸與加工
    • 適配器通過兼容瀏覽器端和 node 端,對外提供統(tǒng)一 api
    • 取消請求這塊,通過外部保留 pendding 狀態(tài),控制 promise 的執(zhí)行時機(jī)

    到此這篇關(guān)于一文掌握ajax、fetch和axios的區(qū)別對比的文章就介紹到這了,更多相關(guān)ajax、fetch和axios的比較內(nèi)容請搜索碩編程以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持碩編程!

    相關(guān)文章