久久综合九色综合97婷婷-美女视频黄频a免费-精品日本一区二区三区在线观看-日韩中文无码有码免费视频-亚洲中文字幕无码专区-扒开双腿疯狂进出爽爽爽动态照片-国产乱理伦片在线观看夜-高清极品美女毛茸茸-欧美寡妇性猛交XXX-国产亚洲精品99在线播放-日韩美女毛片又爽又大毛片,99久久久无码国产精品9,国产成a人片在线观看视频下载,欧美疯狂xxxx吞精视频

有趣生活

當前位置:首頁>職場>axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)

發布時間:2024-01-24閱讀(13)

導讀攔截器一個axios實例上有兩個攔截器,一個是請求攔截器,然后響應攔截器。我們下看下官網的用法:添加攔截器//添加請求攔截器axios.intercepto....攔截器

一個axios實例上有兩個攔截器,一個是請求攔截器, 然后響應攔截器。我們下看下官網的用法:

添加攔截器

// 添加請求攔截器axios.interceptors.request.use(function (config) { // 在發送請求之前做些什么 return config; }, function (error) { // 對請求錯誤做些什么 return Promise.reject(error); });

移除攔截器

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});axios.interceptors.request.eject(myInterceptor);

其實源碼中就是,所有攔截器的執行 所以說肯定有一個forEach方法。

思路理清楚了,現在我們就開始去寫吧。代碼我就直接發出來,然后我在下面注解。

export class InterceptorManager { constructor() { // 存放所有攔截器的棧 this.handlers = [] } use(fulfilled, rejected) { this.handlers.push({ fulfilled, rejected, }) //返回id 便于取消 return this.handlers.length - 1 } // 取消一個攔截器 eject(id) { if (this.handlers[id]) { this.handlers[id] = null } } // 執行棧中所有的hanlder forEach(fn) { this.handlers.forEach((item) => { // 這里為了過濾已經被取消的攔截器,因為已經取消的攔截器被置null if (item) { fn(item) } }) }}

攔截器這個類我們已經初步實現了,現在我們去實現axios 這個類,還是先看下官方文檔,先看用法,再去分析。

axios(config)

// 發送 POST 請求axios({ method: post, url: /user/12345, data: { firstName: Fred, lastName: Flintstone }});

axios(url[, config])

// 發送 GET 請求(默認的方法) axios(/user/12345);

Axios 這個類最核心的方法其實還是 request 這個方法。我們先看下實現吧

class Axios { constructor(config) { this.defaults = config this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager(), } } // 發送一個請求 request(config) { // 這里呢其實就是去處理了 axios(url[,config]) if (typeof config == string) { config = arguments[1] || {} config.url = arguments[0] } else { config = config || {} } // 默認get請求,并且都轉成小寫 if (config.method) { config.method = config.method.toLowerCase() } else { config.method = get } // dispatchRequest 就是發送ajax請求 const chain = [dispatchRequest, undefined] // 發生請求之前加入攔截的 fulfille 和reject 函數 this.interceptors.request.forEach((item) => { chain.unshift(item.fulfilled, item.rejected) }) // 在請求之后增加 fulfilled 和reject 函數 this.interceptors.response.forEach((item) => { chain.push(item.fulfilled, item.rejected) }) // 利用promise的鏈式調用,將參數一層一層傳下去 let promise = Promise.resolve(config) //然后我去遍歷 chain while (chain.length) { // 這里不斷出棧 直到結束為止 promise = promise.then(chain.shift(), chain.shift()) } return promise }}

這里其實就是體現了axios設計的巧妙, 維護一個棧結構 promise 的鏈式調用 實現了 攔截器的功能, 可能有的小伙伴到這里還是不是很能理解,我還是給大家畫一個草圖去模擬下這個過程。

假設我有1個請求攔截器handler和1個響應攔截器handler

一開始我們棧中的數據就兩個

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(1)

這個沒什么問題,由于有攔截器的存在,如果存在的話,那么我們就要往這個棧中加數據,請求攔截器顧名思義要在請求之前所以是unshift。加完請求攔截器我們的棧變成了這樣

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(2)

沒什么問題,然后請求結束后,我們又想對請求之后的數據做處理,所以響應攔截的數據自然是push了。這時候棧結構變成了這樣:

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(3)

然后遍歷整個棧結構,每次出棧都是一對出棧, 因為promise 的then 就是 一個成功,一個失敗嘛。遍歷結束后,返回經過所有處理的promise,然后你就可以拿到最終的值了。

adapter

Adapter: 英文解釋是適配器的意思。這里我就不實現了,我帶大家看一下源碼。adapter 做了一件事非常簡單,就是根據不同的環境 使用不同的請求。如果用戶自定義了adapter,就用config.adapter。否則就是默認是default.adpter.

var adapter = config.adapter || defaults.adapter; return adapter(config).then() ...

繼續往下看deafults.adapter做了什么事情:

function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== undefined) { // For browsers use XHR adapter adapter = require(./adapters/xhr); } else if (typeof process !== undefined && Object.prototype.toString.call(process) === [object process]) { // For node use HTTP adapter adapter = require(./adapters/http); } return adapter;}

其實就是做個選擇:如果是瀏覽器環境:就是用xhr 否則就是node 環境。判斷process是否存在。從寫代碼的角度來說,axios源碼的這里的設計可擴展性非常好。有點像設計模式中的適配器模式, 因為瀏覽器端和node 端 發送請求其實并不一樣, 但是我們不重要,我們不去管他的內部實現,用promise包一層做到對外統一。所以 我們用axios 自定義adapter 器的時候, 一定是返回一個promise。ok請求的方法我在下面模擬寫出。

cancleToken

我首先問大家一個問題,取消請求原生瀏覽器是怎么做到的?有一個abort 方法。可以取消請求。那么axios源碼肯定也是運用了這一點去取消請求。現在瀏覽器其實也支持fetch請求, fetch可以取消請求?很多同學說是不可以的,其實不是?fetch 結合 abortController 可以實現取消fetch請求。我們看下例子:

const controller = new AbortController();const { signal } = controller;fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 1 is complete!`);}).catch(e => { console.warn(`Fetch 1 error: ${e.message}`);});// Wait 2 seconds to abort both requestssetTimeout(() => controller.abort(), 2000);

但是這是個實驗性功能,可惡的ie。所以我們這次還是用原生的瀏覽器xhr基于promise簡單的封裝一下。代碼如下:

export function dispatchRequest(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open(config.method, config.url) xhr.onreadystatechange = function () { if (xhr.status >= 200 && xhr.status <= 300 && xhr.readyState === 4) { resolve(xhr.responseText) } else { reject(失敗了) } } if (config.cancelToken) { // Handle cancellation config.cancelToken.promise.then(function onCanceled(cancel) { if (!xhr) { return } xhr.abort() reject(cancel) // Clean up request xhr = null }) } xhr.send() })}

Axios 源碼里面做了很多處理, 這里我只做了get處理,我主要的目的就是為了axios是如何取消請求的。先看下官方用法:

主要是兩種用法:

使用 cancel token 取消請求

const CancelToken = axios.CancelToken;const source = CancelToken.source();axios.get(/user/12345, { cancelToken: source.token}).catch(function(thrown) { if (axios.isCancel(thrown)) { console.log(Request canceled, thrown.message); } else { // 處理錯誤 }});axios.post(/user/12345, { name: new name}, { cancelToken: source.token})// 取消請求(message 參數是可選的)source.cancel(Operation canceled by the user.);

還可以通過傳遞一個 executor 函數到 CancelToken 的構造函數來創建 cancel token:

const CancelToken = axios.CancelToken;let cancel;axios.get(/user/12345, { cancelToken: new CancelToken(function executor(c) { // executor 函數接收一個 cancel 函數作為參數 cancel = c; })});// cancel the requestcancel();

看了官方用法 和結合axios源碼:我給出以下實現:

export class cancelToken { constructor(exactor) { if (typeof executor !== function) { throw new TypeError(executor must be a function.) } // 這里其實將promise的控制權 交給 cancel 函數 // 同時做了防止多次重復cancel 之前 Redux 還有React 源碼中也有類似的案列 const resolvePromise; this.promise = new Promise(resolve => { resolvePromise = resolve; }) this.reason = undefined; const cancel = (message) => { if(this.reason) { return; } this.reason = cancel message; resolvePromise(this.reason); } exactor(cancel) } throwIfRequested() { if(this.reason) { throw this.reason } } // source 其實本質上是一個語法糖 里面做了封裝 static source() { const cancel; const token = new cancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; }}

截止到這里大體axios 大體功能已經給出。

接下來我就測試下我的手寫axios 有沒有什么問題?

<script type="module" > import Axios from ./axios.js; const config = { url:http://101.132.113.6:3030/api/mock } const axios = new Axios(); axios.request(config).then(res => { console.log(res,0000) }).catch(err => { console.log(err) })</script>

打開瀏覽器看一下結果:

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(4)

成功了ok, 然后我來測試一下攔截器的功能:代碼更新成下面這樣:

import Axios from ./axios.js;const config = { url:http://101.132.113.6:3030/api/mock }const axios = new Axios();// 在axios 實例上掛載屬性const err = () => {}axios.interceptors.request.use((config)=> { console.log(我是請求攔截器1) config.id = 1; return config},err )axios.interceptors.request.use((config)=> { config.id = 2 console.log(我是請求攔截器2) return config},err)axios.interceptors.response.use((data)=> { console.log(我是響應攔截器1,data ) data = 1; return data;},err)axios.interceptors.response.use((data)=> { console.log(我是響應攔截器2,data ) return data},err)axios.request(config).then(res => { // console.log(res,0000) // return res;}).catch(err => { console.log(err)})

ajax 請求的結果 我是resolve(1) ,所以我們看下輸出路徑:

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(5)

沒什么問題, 響應后的數據我加了1。

接下來我來是取消請求的兩種方式

// 第一種方式let cancelFun = undefined;const cancelInstance = new cancelToken((c)=>{ cancelFun = c;});config.cancelToken = cancelInstance;// 50 ms 就取消請求setTimeout(()=>{ cancelFun(取消成功)},50)第二種方式:const { token, cancel } = cancelToken.source();config.cancelToken = token;setTimeout(()=>{ cancel()},50)

axios怎么樣完成前后端數據交互的(web前端面試axios手寫簡易版的axios)(6)

結果都是OK的,至此axios簡單源碼終于搞定了。

反思

本篇文章只是把axios源碼的大體流程走了一遍, axios源碼內部還是做了很多兼容比如:配置優先級:他有一個mergeConfig 方法, 還有數據轉換器。不過這些不影響我們對axios源碼的整體梳理, 源碼中其實有一個createInstance,至于為什么有?我覺得就是為了可擴展性更好, 將來有啥新功能,直接在原有axios的實例的原型鏈上去增加,代碼可維護性強, axios.all spread 都是實例new出來再去掛的,不過都很簡單,沒啥的。有興趣大家自行閱讀。

TAGS標簽:  axios  怎么樣  完成  后端  數據  axios怎么樣完成

Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號-5 TXT地圖HTML地圖XML地圖