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

詳解使用抽象語法樹AST實(shí)現(xiàn)一個(gè)AOP切面邏輯

 更新時(shí)間:2023年04月06日 17:03:19   作者:頭疼腦脹的代碼搬運(yùn)工  
這篇文章主要為大家介紹了使用抽象語法樹AST實(shí)現(xiàn)一個(gè)AOP切面邏輯的簡(jiǎn)單方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

開篇

AST 功能很靈活,可以通過改變一些自定義結(jié)構(gòu)便可以輸入自定義的功能,下面簡(jiǎn)單的展示下如何利用抽象語法樹AST實(shí)現(xiàn)一個(gè)AOP切面邏輯

一、實(shí)現(xiàn)目的

js 文件下的全部方法添加一個(gè)開始事件和一個(gè)結(jié)束事件并傳入方法名,以便監(jiān)聽某個(gè)方法的調(diào)用。

1、work.js

function eat(){
    let food = "apple"
    let time = '2小時(shí)'
    return '吃' + food + '用時(shí)' + time
}
function work(){
}
console.log(eat())

控制臺(tái)打印

可以看到,輸入了執(zhí)行 eat 方法的開始事件及結(jié)束事件。其實(shí),這個(gè)過程就是 work.js 轉(zhuǎn)成語法樹后,對(duì)方法節(jié)點(diǎn)進(jìn)行了處理,添加了兩個(gè)切面方法:startend 事件。

2、aop.js

這個(gè)文件用來聲明 startend 事件。

function start(funcName){
    console.log('開始執(zhí)行:' + funcName + '方法')
}
function end(funcName){
    console.log('執(zhí)行結(jié)束:' + funcName + '方法')
}

二、利用語法樹添加切面事件

//文件操作工具
const fs = require('fs');
//JS代碼轉(zhuǎn)語法樹工具
const parser = require('./babel-core/node_modules/babylon');
//語法樹遍歷工具
const traverse = require('./babel-core/node_modules/babel-traverse');
//語法樹轉(zhuǎn)JS代碼工具
const generator = require('./babel-core/node_modules/babel-generator');
//聲明語法樹類型工具
const t = require('./babel-core/node_modules/babel-types');
//獲取aop代碼
let aop = fs.readFileSync('./aop.js','utf-8')
//獲取需要添加切面的代碼
let content = fs.readFileSync('./work.js','utf-8')
//將需要添加切面的代碼轉(zhuǎn)換為語法樹
let ast = parser.parse(content,{
    sourceType:'script'
})
//遍歷指定語法樹時(shí)操作項(xiàng)(這里遍歷的指定節(jié)點(diǎn)是FunctionDeclaration方法)
const visitor = {
    FunctionDeclaration:({ node }) => {
        //獲取每個(gè)方法體里面的節(jié)點(diǎn)
        let funcBody = node.body.body
        //創(chuàng)建一個(gè)名為start,參數(shù)為當(dāng)前方法名的執(zhí)行節(jié)點(diǎn),后面的參數(shù)為創(chuàng)建一個(gè)名為start方法的參數(shù)
        let start = t.callExpression(t.identifier('start'), [t.identifier(`"${node.id.name}"`)])
        //添加到方法的最前面
        funcBody.unshift(start)
        //判斷最后一個(gè)節(jié)點(diǎn)是不是return,方式結(jié)束事件調(diào)用節(jié)點(diǎn)在最后無法調(diào)用。
        let lastNode = funcBody.slice(-1)
        //創(chuàng)建一個(gè)名為end,參數(shù)為當(dāng)前方法名的執(zhí)行節(jié)點(diǎn),后面的參數(shù)為end方法的參數(shù)
        let end = t.callExpression(t.identifier('end'), [t.identifier(`"${node.id.name}"`)])
        //設(shè)定end節(jié)點(diǎn)添加的位置
        let insertEndEventPosition = (funcBody.length)
        if(lastNode[0].type == 'ReturnStatement'){
            //放在return節(jié)點(diǎn)的前面
            insertEndEventPosition -= 1
        }
        //添加end節(jié)點(diǎn)
        funcBody.splice(insertEndEventPosition,0,end)
    }
}
//開始遍歷操作語法樹
traverse.default(ast,visitor)
//將處理完的語法樹再次轉(zhuǎn)換為JS代碼
let codeResult = generator.default(ast)
//這里需要添加aop里面的兩個(gè)切面事件到最終的JS代碼里。
let outFileCode = aop + '\n\n' + codeResult.code
// 寫入文件操作
fs.mkdir('cache',(err)=>{
    if(!err){
        fs.writeFile('cache/main.js',outFileCode,(err)=>{
            if(!err){
                console.log('文件創(chuàng)建完成')
            }
        })
    }
})

上面的代碼執(zhí)行完后,看下 main.js 生成的代碼內(nèi)容。

function start(funcName){
    console.log('開始執(zhí)行:' + funcName + '方法')
}
function end(funcName){
    console.log('執(zhí)行結(jié)束:' + funcName + '方法')
}
function eat() {
    start("eat")
    let food = "apple";
    let time = '2小時(shí)';
    end("eat")
    return '吃' + food + '用時(shí)' + time;
}
function work() {
    start("work")
    end("work")
}
console.log(eat());

相比較之前的 work.js 文件,添加了兩個(gè)切面方法的同時(shí),保證每個(gè)方法都添加了 startend 事件。這樣再調(diào)用的時(shí)候便可直接在執(zhí)行前后操作其他任務(wù)了。

三、總結(jié)與思考

其實(shí)上面的操作人工也可以直接操作,但是,將一切重復(fù)單一的工作交給程序,這或許是代碼存在的真正意義。一個(gè)簡(jiǎn)單的例子或許能打開一個(gè)新的世界,雖然,每一行代碼都是獨(dú)一無二的,但是如果追本溯源,最初并且真切的思想?yún)s是相通的

以上就是詳解使用抽象語法樹AST實(shí)現(xiàn)一個(gè)AOP切面邏輯的詳細(xì)內(nèi)容,更多關(guān)于AST抽象語法樹實(shí)現(xiàn)AOP的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Node.js?中的?module.exports?與?exports區(qū)別介紹

    Node.js?中的?module.exports?與?exports區(qū)別介紹

    這篇文章主要介紹了Node.js中的module.exports與exports區(qū)別介紹,每個(gè)模塊中都有module對(duì)象,存放了當(dāng)前模塊相關(guān)的信息,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-09-09
  • 提升node.js中使用redis的性能遇到的問題及解決方法

    提升node.js中使用redis的性能遇到的問題及解決方法

    本文中提到的node redis client采用的基于node-redis封裝的二方包,因此問題排查也基于node-redis這個(gè)模塊。接下來通過本文給大家分享提升node.js中使用redis的性能
    2018-10-10
  • 淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求

    淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求

    這篇文章主要介紹了淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • 使用puppeteer破解極驗(yàn)的滑動(dòng)驗(yàn)證碼

    使用puppeteer破解極驗(yàn)的滑動(dòng)驗(yàn)證碼

    這篇文章主要介紹了利用puppeteer破解極驗(yàn)的滑動(dòng)驗(yàn)證功能,基本流程代碼實(shí)現(xiàn)給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-02-02
  • Nodejs讓異步變成同步的方法

    Nodejs讓異步變成同步的方法

    今天小編就為大家分享一篇關(guān)于Nodejs讓異步變成同步的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 進(jìn)階之初探nodeJS

    進(jìn)階之初探nodeJS

    本文主要介紹了nodeJS的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • Node.js+jade+mongodb+mongoose實(shí)現(xiàn)爬蟲分離入庫(kù)與生成靜態(tài)文件的方法

    Node.js+jade+mongodb+mongoose實(shí)現(xiàn)爬蟲分離入庫(kù)與生成靜態(tài)文件的方法

    下面小編就為大家?guī)硪黄狽ode.js+jade+mongodb+mongoose實(shí)現(xiàn)爬蟲分離入庫(kù)與生成靜態(tài)文件的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Node.js用readline模塊實(shí)現(xiàn)輸入輸出

    Node.js用readline模塊實(shí)現(xiàn)輸入輸出

    在學(xué)C++的時(shí)候,有cout和cin,Java也有println和Scanner控件,Node.js也有如同C++和Java的標(biāo)準(zhǔn)輸入,當(dāng)然,是用JavaScript實(shí)現(xiàn)的,它就是Readline模塊。下面這篇文章就給大家詳細(xì)介紹一下readline模塊,來實(shí)現(xiàn)Node.js的控制臺(tái)輸入輸出。有需要的可以參考借鑒。
    2016-12-12
  • 基于Nodejs的Tcp封包和解包的理解

    基于Nodejs的Tcp封包和解包的理解

    這篇文章主要介紹了基于Nodejs的Tcp封包和解包的理解,詳細(xì)的介紹了tcp的分包與拆包并實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • node.js平臺(tái)下利用cookie實(shí)現(xiàn)記住密碼登陸(Express+Ejs+Mysql)

    node.js平臺(tái)下利用cookie實(shí)現(xiàn)記住密碼登陸(Express+Ejs+Mysql)

    這篇文章主要介紹了node.js平臺(tái)下利用cookie實(shí)現(xiàn)記住密碼登陸(Express+Ejs+Mysql),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04

最新評(píng)論