日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【axios源码】- 取消请求cancel模块研读解析

發(fā)布時(shí)間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【axios源码】- 取消请求cancel模块研读解析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首發(fā)于我的公眾號「前端面壁者」,歡迎關(guān)注。

基于 TC39 的 cancelable promises proposal 提議封裝,但是這個(gè)提議已經(jīng)被發(fā)起人自己取消了,據(jù)說是因?yàn)?Google 內(nèi)部反對意見很大,詳情可以到相關(guān) issueWhy was this proposal withdrawn?看一下。

一、環(huán)境準(zhǔn)備

  • axios 版本 v0.24.0

  • 通過 github1s 網(wǎng)頁可以 查看 axios 源碼

  • 調(diào)試需要 clone 到本地

git clone https://github.com/axios/axios.gitcd axiosnpm starthttp://localhost:3000/

二、函數(shù)研讀

cancel 模塊包含三個(gè)文件Cancel、CancelToken、isCancel

├─cancel // 取消請求 │ Cancel.js │ CancelToken.js │ isCancel.js

1. Cancel 類

A Cancel is an object that is thrown when an operation is canceled.
當(dāng)操作被取消時(shí)會拋出一個(gè) Cancel 對象

"use strict";/*** A `Cancel` is an object that is thrown when an operation is canceled.** @class* @param {string=} message The message.*/ function Cancel(message) {this.message = message; }Cancel.prototype.toString = function toString() {return "Cancel" + (this.message ? ": " + this.message : ""); };Cancel.prototype.__CANCEL__ = true;module.exports = Cancel;
  • 只有 8 行代碼,實(shí)現(xiàn)了一個(gè)Cancel 類
  • 包含一個(gè)原型方法 toString ,一個(gè)實(shí)例屬性__CANCEL__
  • 實(shí)例屬性__CANCEL__被設(shè)定為 true,是 Cancel 類的標(biāo)志

Tips:我們知道一個(gè)請求會有三種狀態(tài)請求前、請求中、請求結(jié)束,取消動(dòng)作可能發(fā)生在其中的任何一個(gè)階段。不同階段對應(yīng)的取消邏輯在axios中是不一樣的,且在請求中這個(gè)階段,函數(shù)執(zhí)行的邏輯位置也不一樣,所以當(dāng)我們發(fā)起取消請求時(shí),axios需要一種機(jī)制獲知當(dāng)前網(wǎng)絡(luò)請求走到了哪個(gè)階段的哪個(gè)位置才能執(zhí)行對應(yīng)的取消和返回邏輯,Cancel 類就是這樣一個(gè)機(jī)制。

2. isCancel 函數(shù)

"use strict";module.exports = function isCancel(value) {return !!(value && value.__CANCEL__); };
  • 只有 3 行代碼,通過 Cancel 的實(shí)例屬性__CANCEL__ 來判斷value是否為 Cancel 實(shí)例
  • 導(dǎo)出一個(gè) isCancel 函數(shù),如果入?yún)?val 不是 Cancel類會返回 false,否則返回 true

3. CancelToken 類

A CancelToken is an object that can be used to request cancellation of an operation.
CancelToken 是被用于取消請求操作的類

參考文章林景宜的記事本提到這是一個(gè)讓人一頭霧水的類,剛看的時(shí)候筆者也有同感,雖然經(jīng)過一些剖析筆者已經(jīng)分析的盡可能詳細(xì)(自我感覺良好 🐶),但在觀看之前還是推薦不了解設(shè)計(jì)模式的小伙伴去了解一下其中的發(fā)布/訂閱模式,會有助于理解

【2.1】 引入 Cancel 類

"use strict";var Cancel = require("./Cancel");

【2.2】 內(nèi)部函數(shù) CancelToken

兩段this.promise.then并不是取消邏輯,暫時(shí)先忽略

/*** A `CancelToken` is an object that can be used to request cancellation of an operation.** @class* @param {Function} executor The executor function.*/ function CancelToken(executor) {if (typeof executor !== "function") {throw new TypeError("executor must be a function.");}var resolvePromise;this.promise = new Promise(function promiseExecutor(resolve) {resolvePromise = resolve;});var token = this;// eslint-disable-next-line func-namesthis.promise.then(function (cancel) {if (!token._listeners) return;var i;var l = token._listeners.length;for (i = 0; i < l; i++) {token._listeners[i](cancel);}token._listeners = null;});// eslint-disable-next-line func-namesthis.promise.then = function (onfulfilled) {var _resolve;// eslint-disable-next-line func-namesvar promise = new Promise(function (resolve) {token.subscribe(resolve);_resolve = resolve;}).then(onfulfilled);promise.cancel = function reject() {token.unsubscribe(_resolve);};return promise;};executor(function cancel(message) {if (token.reason) {// Cancellation has already been requestedreturn;}token.reason = new Cancel(message);resolvePromise(token.reason);}); }

接下來按行分析

  • 1. 首先判斷入?yún)xecutor是否是 function 類型,如果不是會拋出類型錯(cuò) TypeError

    • 為什么入?yún)xecutor是一個(gè)函數(shù)?
    • 答:CancelToken通過發(fā)布訂閱模式來實(shí)現(xiàn)傳遞取消信息,訂閱者把自己想訂閱的事件cancel/c注冊到調(diào)度中心CancelToken,當(dāng)適配器返回信息時(shí)發(fā)布者發(fā)布到調(diào)度中心CancelToken,調(diào)度中心再統(tǒng)一調(diào)度執(zhí)行訂閱者注冊到調(diào)度中心的處理代碼cancel。這也就理解了這個(gè)函數(shù)為什么叫executor-執(zhí)行器。
  • 2. 創(chuàng)建全局變量resolvePromise

    • 為什么要?jiǎng)?chuàng)建這個(gè)變量?為什么要以全局的方式創(chuàng)建?
    • 答:為了拿到resolve便于后續(xù)的鏈?zhǔn)秸{(diào)用,且只有全局變量才能穿過函數(shù)作用域拿到 resolve 值
  • 3. 使用new Promise()創(chuàng)建函數(shù)promiseExecutor的實(shí)例對象,表明executor是一個(gè)異步函數(shù),其返回值resolve傳遞給全局變量resolvePromise,調(diào)用時(shí)可使用this.promise.then()獲取返回值resolve或直接使用resolvePromise

    • 為什么創(chuàng)建 promise 對象?
    • 因?yàn)檎嬲∠埱蟮膭?dòng)作request.abort()在適配器xhr.js或http.js里觸發(fā),這是一個(gè)異步的方法,當(dāng)這個(gè)動(dòng)作發(fā)生后我們才能在 resolve 中拿到返回值
  • 4. 創(chuàng)建全局變量token表示當(dāng)前CancelToken的實(shí)例

  • 5. executor執(zhí)行器執(zhí)行訂閱者事件cancel ,該方法入?yún)essage來自用戶調(diào)用時(shí)傳參

  • 6. 訂閱者事件cancel在執(zhí)行時(shí)首先會判斷實(shí)例token是否存在reason屬性值,如果存在直接返回,否則使用new Cancel()聲明一個(gè) cancel 類給reason賦值

    • 為什么用new Cancel()聲明一個(gè) cancel 類給reason賦值?
    • 答:這樣reason的原型鏈上會掛載一個(gè)__CANCEL__表示 cancel 類,同時(shí)配合resolvePromise執(zhí)行會把this.promise實(shí)例狀態(tài)改為fulfilled,這意味著是用戶主動(dòng)取消請求返回的信息而非因?yàn)槠渌惓7祷?#xff08;會把this.promise實(shí)例狀態(tài)改為reject)

CancelToken 構(gòu)造函數(shù)就是一個(gè)發(fā)布訂閱函數(shù),通過發(fā)布訂閱觸發(fā)向外 resolve 或者拋出錯(cuò)誤(reject),Promise 鏈?zhǔn)浇Y(jié)構(gòu)成功拿到resolve值或者 catch 到錯(cuò)誤后,會返回用戶的輸入message或停止繼續(xù)執(zhí)行并執(zhí)行錯(cuò)誤回調(diào)。

【2.3】 添加原型方法 throwIfRequested

/*** Throws a `Cancel` if cancellation has been requested.*/ CancelToken.prototype.throwIfRequested = function throwIfRequested() {if (this.reason) {throw this.reason;} };
  • 如果已觸發(fā)取消事件,則拋出一個(gè)錯(cuò)誤信息

【2.4】 source

/*** Returns an object that contains a new `CancelToken` and a function that, when called,* cancels the `CancelToken`.*/ CancelToken.source = function source() {var cancel;var token = new CancelToken(function executor(c) {cancel = c;});return {token: token,cancel: cancel,}; };
  • 初始化時(shí)返回值是一個(gè)對象,包含新的CancelToken對象 token 和函數(shù) cancel
  • 執(zhí)行時(shí)訂閱者會將訂閱事件c注冊到調(diào)度中心CancelToken,調(diào)度中心在執(zhí)行器executor中立即執(zhí)行訂閱者事件
  • cancel函數(shù)通過全局作用域拿到c,通過 return 暴露給用戶一個(gè)訂閱事件的入口

【2.5】 添加原型方法 subscribe

/*** Subscribe to the cancel signal*/CancelToken.prototype.subscribe = function subscribe(listener) {if (this.reason) {listener(this.reason);return;}if (this._listeners) {this._listeners.push(listener);} else {this._listeners = [listener];} };
  • 添加訂閱時(shí)執(zhí)行的函數(shù),訂閱事件cancel被執(zhí)行時(shí),會向當(dāng)前實(shí)例的_listeners屬性上追加鏈?zhǔn)秸{(diào)用的返回值

【2.6】 添加原型方法 unsubscribe

/*** Unsubscribe from the cancel signal*/CancelToken.prototype.unsubscribe = function unsubscribe(listener) {if (!this._listeners) {return;}var index = this._listeners.indexOf(listener);if (index !== -1) {this._listeners.splice(index, 1);} };
  • 添加訂閱時(shí)的執(zhí)行的函數(shù),訂閱事件cancel被執(zhí)行時(shí),如果是重復(fù)取消就移除當(dāng)前實(shí)例的_listeners屬性上對應(yīng)位置的鏈?zhǔn)秸{(diào)用

三、參考

1. 仙凌閣的文章詳細(xì) Axios 源碼解讀

2. 林景宜的文章林景宜的記事本 - Axios 源碼解析(二):通用工具方法

3. 若川的文章學(xué)習(xí) axios 源碼整體架構(gòu),打造屬于自己的請求庫

4. 杰凌的文章深入解讀 axios 源碼

5. 海角在眼前的文章設(shè)計(jì)模式(三):觀察者模式與發(fā)布/訂閱模式區(qū)別

總結(jié)

以上是生活随笔為你收集整理的【axios源码】- 取消请求cancel模块研读解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。