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

JavaScript使用AOP編程思想實現(xiàn)監(jiān)聽HTTP請求

 更新時間:2024年02月28日 15:50:56   作者:plutoLam  
這篇文章主要為大家詳細(xì)介紹了如何在JavaScript使用AOP編程思想實現(xiàn)監(jiān)聽HTTP請求,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

AOP切面編程的概念

AOP這個概念來源于JavaSpring框架,是Spring為了解決OOP(面向?qū)ο缶幊棠J剑┟鎸σ恍I(yè)務(wù)場景的限制而開發(fā)來的,下面就讓我用JavaScript代替Java來解釋一下AOP

比如我現(xiàn)在使用OOP寫法新建一個讀取數(shù)據(jù)的業(yè)務(wù)組件,分別有讀取data,更新data刪除data三個方法:

class DataService {
  constructor(ctx) {
    this.ctx = ctx;
  }
  createData() {
    ctx.createData();
  }
  updateData() {
    ctx.updateData();
  }
  deleteData() {
    ctx.deleteData();
  }
}

對于每個接口,業(yè)務(wù)可能會有一些相同的操作,如日志記錄、數(shù)據(jù)檢驗、安全驗證等,那么代碼就會像下面這樣

class DataService {
  constructor(ctx) {
    this.ctx = ctx;
  }
  createData() {
    ctx.dataCheck();
    ctx.createData();
  }
  updateData() {
    ctx.dataCheck();
    ctx.updateData();
  }
  deleteData() {
    ctx.dataCheck();
    ctx.deleteData();
  }
}

一個相同的功能在很多不同的方法中以相同的方式出現(xiàn),這樣顯然不符合編碼的簡潔性和易讀性。 有一種解決方法是使用Proxy模式,為了保持我們的代碼中一個類只負(fù)責(zé)一件事的原則,新建一個新的類繼承于DataService,在這個類中為每個方法都加上dataCheck

class CheckDataService extends DataService {
  constructor(ctx) {
    super(ctx)
  }
  createData() {
    ctx.dataCheck();
    ctx.createData();
  }
  updateData() {
    ctx.dataCheck();
    ctx.updateData();
  }
  deleteData() {
    ctx.dataCheck();
    ctx.deleteData();
  }
}

這樣的做法缺點是比較麻煩,每個Proxy中都要重復(fù)執(zhí)行父類的方法。

那么這時就有了AOP,其基本原理是在Spring中某個類的運行期的前期或者后期插入某些邏輯,在Spring中可以通過注解的形式,讓Spring容器啟動時實現(xiàn)自動注入,如下面代碼片段

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect // 聲明為切面
@Component // 讓Spring能夠掃描并創(chuàng)建切面實例
public class LoggingAspect {

    // 在UserService的每個public方法前執(zhí)行l(wèi)ogBefore
    @Before("execution(public * com.example.UserService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Logging before the method executes");
    }

    // 在UserService的每個public方法前執(zhí)行l(wèi)ogAfter
    @After("execution(public * com.example.UserService.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("Logging after the method executes");
    }
}

// UserService
import org.springframework.stereotype.Component;

@Component // 聲明為一個Spring管理的組件
public class UserService {

    public void login() {
        System.out.println("Doing some important work");
    }
}

但是JS沒有在底層實現(xiàn)這些東西,所以我們只能自己改造。

在JavaScript中實現(xiàn)AOP

思路是這樣的,我們將某個需要切入的方法進行重寫,在重寫后的函數(shù)中切入相關(guān)邏輯就行了

/**
 * 重寫對象上面的某個屬性
 * @param targetObject 需要被重寫的對象
 * @param propertyName 需要被重寫對象的 key
 * @param newImplementation 以原有的函數(shù)作為參數(shù),執(zhí)行并重寫原有函數(shù)
 */
function overrideProperty(
  targetObject,
  propertyName,
  newImplementation,
) {
  if (targetObject === undefined) return // 若當(dāng)前對象不存在
  if (propertyName in targetObject) {  // 若當(dāng)前對象存在當(dāng)前屬性
    const originalFunction = targetObject[propertyName]
    const modifiedFunction = newImplementation(originalFunction) // 把原本的函數(shù)傳入
    if (typeof modifiedFunction == 'function') {
      targetObject[propertyName] = modifiedFunction
    }
  }
}

先寫一個公共方法,去重寫對象上的某個屬性,這樣我們可以調(diào)用overrideProperty去重寫任意對象上的任何方法。 現(xiàn)在用overrideProperty重寫一下window上的fetch方法

overrideProperty(window, 'fetch', originalFetch => {
  return function (...args) {
    // 在fetch發(fā)起前做些什么
    return originalFetch.apply(this, args).then((res) => {
      // 在fetch完成后做些什么
      return res
    })
  }
})

可以看到我們第三個參數(shù)傳入一個函數(shù)并返回一個函數(shù),這個返回的函數(shù)就是重寫完成的fetch方法,只要在項目初始化時調(diào)用overrideProperty,那么以后調(diào)用fetch時都會執(zhí)行。 是不是感覺這樣寫也挺麻煩的,我們換一種寫法:

function overrideProperty(
  targetObject,
  propertyName,
  context,
) {
  if (targetObject === undefined) return
  if (propertyName in targetObject) {
    const originalFunction = targetObject[propertyName]
    function reactorFn(...args) {
      this.before && this.before();
      originalFunction.apply(context, args);
      this.after && this.after();
    }
    targetObject[propertyName] = reactorFn;
    reactorFn.before = (fn) => {
      this.before = fn;
      return reactorFn
    };
    reactorFn.after = (fn) => {
      this.after = fn;
      return reactorFn;
    };
    return reactorFn;
  }
}

overrideProperty(window, 'alert', window).before(() => {
  console.log('before')
}).after(() => {
  console.log('after')
})

alert('test')

這樣子就可以通過鏈?zhǔn)秸{(diào)用的方式來定義beforeafter的回調(diào)函數(shù)了,但是這只適用于同步執(zhí)行的方法,對于fetch這種異步的返回Promise的方法,為了在Promise.then中執(zhí)行after,又得專門寫一個重寫函數(shù),大家就根據(jù)自己的項目情況來選擇不同就寫法吧。

監(jiān)聽HTTP請求

瀏覽器中主要的HTTP請求通過XMLHttpRequestfetch發(fā)出,在上面我們已經(jīng)監(jiān)聽了fetch,接下來我們監(jiān)聽一下XMLHttpRequest。 一般使用XMLHttpRequest發(fā)送HTTP請求會調(diào)用open方法,最后調(diào)用send方法,所以我們監(jiān)聽開始時的open和最后的send 所以我們重寫這兩個方法

// 重寫open
overrideProperty(XMLHttpRequest.prototype, 'open', (originalOpen) => {
  return function (...args) {
    // do something
    originalOpen.apply(this, args)
  }
})

// 重寫send
overrideProperty(XMLHttpRequest.prototype, 'send', (originalSend) => {
  return function (...args) {
    // do something
    originalSend.apply(this, args)
  }
})

當(dāng)send后,xhr對象上的readyState會經(jīng)歷四個狀態(tài),分別是: 0 (UNSENT): XMLHttpRequest 對象已經(jīng)創(chuàng)建,但 open() 方法還沒有被調(diào)用。 1 (OPENED): open() 方法已經(jīng)被調(diào)用。在這個狀態(tài)下,你可以通過設(shè)置請求頭和請求方法來配置請求。 2 (HEADERS_RECEIVED): send() 方法已經(jīng)被調(diào)用,并且頭部和狀態(tài)已經(jīng)可獲得。 3 (LOADING): 下載中;responseText 屬性已經(jīng)包含部分?jǐn)?shù)據(jù)。 4 (DONE): 請求操作已經(jīng)完成。

我們直接監(jiān)聽readyState為4(DONE)的完成狀態(tài)即可

// 重寫send
overrideProperty(XMLHttpRequest.prototype, 'send', (originalSend) => {
  return function (...args) {
    // do something
    originalSend.apply(this, args)
    // 監(jiān)聽 readystatechange 事件
    this.addEventListener("readystatechange", function () {
      // 檢查 readyState 的狀態(tài)
      if (this.readyState === XMLHttpRequest.DONE) {
        // 請求已完成,檢查狀態(tài)碼
        if (this.status === 200) {
          // 請求成功,處理響應(yīng)數(shù)據(jù)
          console.log("請求成功:", this.responseText);
        } else {
          // 請求失敗,處理錯誤
          console.log("請求失敗:", this.status);
        }
      }
    });
  }
})

這樣當(dāng)我們當(dāng)前頁面有fetch請求和xhr請求時,都可以被捕獲到。

總結(jié)

本文從Spring出發(fā),介紹了AOP面向切面編程的由來,又用JavaScript演示了AOP編程的優(yōu)勢,最后使用AOP編程實現(xiàn)了HTTP請求的監(jiān)聽,這大家的平時的開發(fā)中也可以靈活運用。

到此這篇關(guān)于JavaScript使用AOP編程思想實現(xiàn)監(jiān)聽HTTP請求的文章就介紹到這了,更多相關(guān)JavaScript監(jiān)聽HTTP請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 判斷數(shù)組的最佳方法(推薦)

    判斷數(shù)組的最佳方法(推薦)

    下面小編就為大家?guī)硪黄猨s判斷數(shù)組的最佳方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • undefined與null的區(qū)別示例詳解

    undefined與null的區(qū)別示例詳解

    這篇文章主要為大家介紹了undefined與null的區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • js禁止瀏覽器頁面后退功能的實例(推薦)

    js禁止瀏覽器頁面后退功能的實例(推薦)

    下面小編就為大家?guī)硪黄猨s禁止瀏覽器頁面后退功能的實例(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 詳解如何在webpack中做預(yù)渲染降低首屏空白時間

    詳解如何在webpack中做預(yù)渲染降低首屏空白時間

    這篇文章主要介紹了詳解如何在webpack中做預(yù)渲染降低首屏空白時間,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • 一定有你會用到的JavaScript一行代碼實用技巧總結(jié)

    一定有你會用到的JavaScript一行代碼實用技巧總結(jié)

    這篇文章主要為大家介紹了一定有你會用到的JavaScript一行代碼總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 用javascript判斷IE版本號簡單實用且向后兼容

    用javascript判斷IE版本號簡單實用且向后兼容

    項目中需要判斷IE版本號,又因為 jQuery 2.0 去除了對瀏覽器版本號的判斷于是就看到一老外寫的一段代碼,下面與大家分享下
    2013-09-09
  • 使用webpack編譯es6代碼的方法步驟

    使用webpack編譯es6代碼的方法步驟

    這篇文章主要介紹了使用webpack編譯es6代碼的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • 用JavaScript實現(xiàn)類似于ListBox功能示例代碼

    用JavaScript實現(xiàn)類似于ListBox功能示例代碼

    這篇文章主要介紹了用JavaScript實現(xiàn)類似于ListBox功能,需要的朋友可以參考下
    2014-03-03
  • JavaScript日期處理類庫moment()獲取時間

    JavaScript日期處理類庫moment()獲取時間

    moment.js是一個廣泛使用的JavaScript日期處理庫,便于開發(fā)者進行日期的解析、驗證、操作和格式化,通過引用并設(shè)置區(qū)域,可以輕松實現(xiàn)本地化日期和時間的處理,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • 淺談js里面的InttoStr和StrtoInt

    淺談js里面的InttoStr和StrtoInt

    下面小編就為大家?guī)硪黄獪\談js里面的InttoStr和StrtoInt。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06

最新評論