国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

詳解在Javascript中進行面向切面編程

2024-05-06 16:50:21
字體:
來源:轉載
供稿:網友

面向切面編程(Aspect-oriented programming,AOP)是一種編程范式。做后端 Java web 的同學,特別是用過 Spring 的同學肯定對它非常熟悉。AOP 是 Spring 框架里面其中一個重要概念。可是在 Javascript 中,AOP 是一個經常被忽視的技術點。

場景

假設你現在有一個牛逼的日歷彈窗,有一天,老板讓你統計一下每天這個彈窗里面某個按鈕的點擊數,于是你在彈窗里做了埋點;

過了一個星期,老板說用戶反饋這個彈窗好慢,各種卡頓。你想看一下某個函數的平均執行時間,于是你又在彈窗里加上了性能統計代碼。

時間久了,你會發現你的業務邏輯里包含了大量的和業務無關的東西,即使是一些你已經封裝過的函數。
那么 AOP 就是為了解決這類問題而存在的。

關注點分離

分離業務代碼和數據統計代碼(非業務代碼),無論在什么語言中,都是AOP的經典應用之一。從核心關注點中分離出橫切關注點,是 AOP 的核心概念。
在前端的常見需求中,有以下一些業務可以使用 AOP 將其從核心關注點中分離出來

  1. Node.js 日志log
  2. 埋點、數據上報
  3. 性能分析、統計函數執行時間
  4. 給ajax請求動態添加參數、動態改變函數參數
  5. 分離表單請求和驗證
  6. 防抖與節流

 裝飾器(Decorator)

提到 AOP 就要說到裝飾器模式,AOP 經常會和裝飾器模式混為一談。

在ES6之前,要使用裝飾器模式,通常通過Function.prototype.before做前置裝飾,和Function.prototype.after做后置裝飾(見《Javascript設計模式和開發實踐》)。

Javascript 引入的 Decorator ,和 Java 的注解在語法上很類似,不過在語義上沒有一丁點關系。Decorator 提案提供了對 Javascript 的類和類里的方法進行裝飾的能力。(盡管只是在編譯時運行的函數語法糖)

埋點數據上報

因為在使用 React 的實際開發中有大量基于 Class 的 Component,所以我這里用 React 來舉例。
比如現在頁面中有一個button,點擊這個button會彈出一個彈窗,與此同時要進行數據上報,來統計有多少用戶點擊了這個登錄button。

import React, { Component } from 'react';import send from './send';class Dialog extends Component {  constructor(props) {    super(props);  }  @send  showDialog(content) {    // do things  }  render() {    return (      <button onClick={() => this.showDialog('show dialog')}>showDialog</button>    )  }}export default Dialog;

上面代碼引用了@send裝飾器,他會修改這個 Class 上的原型方法,下面是@send裝飾器的實現

export default function send(target, name, descriptor) {  let oldValue = descriptor.value;  descriptor.value = function () {    console.log(`before calling ${name} with`, arguments);    return oldValue.apply(this, arguments);  };  return descriptor;}

在按鈕點擊后執行showDialog前,可以執行我們想要的切面操作,我們可以將埋點,數據上報相關代碼封裝在這個裝飾器里面來實現 AOP。

前置裝飾和后置裝飾

上面的send這個裝飾器其實是一個前置裝飾器,我們可以將它再封裝一下使它可以前置執行任意函數。

function before(beforeFn = function () { }) {  return function (target, name, descriptor) {    let oldValue = descriptor.value;    descriptor.value = function () {      beforeFn.apply(this, arguments);      return oldValue.apply(this, arguments);    };    return descriptor;  }}

這樣我們就可以使用@before裝飾器在一個原型方法前切入任意的非業務代碼。

function beforeLog() {  console.log(`before calling ${name} with`, arguments);}class Dialog {  ...  @before(beforeLog)  showDialog(content) {    // do things  }  ...}

和@before裝飾器類似,可以實現一個@after后置裝飾器,只是函數的執行順序不一樣。

function after(afterFn = function () { }) {  return function (target, name, descriptor) {    let oldValue = descriptor.value;    descriptor.value = function () {      let ret = oldValue.apply(this, arguments);      afterFn.apply(this, arguments);      return ret;    };    return descriptor;  }}

性能分析

有時候我們想統計一段代碼在用戶側的執行時間,但是又不想將打點代碼嵌入到業務代碼中,同樣可以利用裝飾器來做 AOP。

function measure(target, name, descriptor) {  let oldValue = descriptor.value;  descriptor.value = function () {    let ret = oldValue.apply(this, arguments);    performance.mark("startWork");    afterFn.apply(this, arguments);    performance.mark("endWork");    performance.measure("work", "startWork", "endWork");    performance     .getEntries()     .map(entry => JSON.stringify(entry, null, 2))     .forEach(json => console.log(json));    return ret;  };  return descriptor;}

在要統計執行時間的類方法前面加上@measure就行了,這樣做性能統計的代碼就不會侵入到業務代碼中。

class Dialog {  ...  @measure  showDialog(content) {    // do things  }  ...}

小結

面向切面編程的重點就是將核心關注面分離出橫切關注面,前端可以用 AOP 優雅的來組織數據上報、性能分析、統計函數的執行時間、動態改變函數參數、插件式的表單驗證等代碼。

以上所述是小編給大家介紹的Javascript面向切面編程詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 恩施市| 荆州市| 利川市| 金山区| 濮阳市| 徐汇区| 宁都县| 玉山县| 长海县| 姜堰市| 吴江市| 信丰县| 保德县| 瑞丽市| 会东县| 马关县| 八宿县| 山西省| 瓦房店市| 当阳市| 新密市| 甘德县| 芮城县| 德昌县| 萝北县| 项城市| 定边县| 苏尼特右旗| 枣庄市| 刚察县| 新化县| 河北区| 巨野县| 广西| 光泽县| 江西省| 通河县| 上饶县| 锡林郭勒盟| 新密市| 崇州市|