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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dojo/aspect源码解析

發布時間:2024/4/13 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dojo/aspect源码解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  dojo/aspect模塊是dojo框架中對于AOP的實現。關于AOP的詳細解釋請讀者另行查看其它資料,這里簡單復習一下AOP中的基本概念:

  • 切面(Aspect):其實就是共有功能的實現。如日志切面、權限切面、事務切面等。
  • 通知(Advice):是切面的具體實現。以目標方法為參照點,根據放置的地方不同,可分為前置通知(Before)、后置通知(After)與環繞通知(Around)。
  • 連接點(Joinpoint):就是程序在運行過程中能夠插入切面的地點。
  • 目標對象(Target):就是那些即將切入切面的對象,也就是那些被通知的對象。這些對象中已經只剩下干干凈凈的核心業務邏輯代碼了,所有的共有功能代碼等待AOP容器的切入。
  • 代理對象(Proxy):將通知應用到目標對象之后被動態創建的對象。可以簡單地理解為,代理對象的功能等于目標對象的核心業務邏輯功能加上共有功能。代理對象對于使用者而言是透明的,是程序運行過程中的產物。
  • 織入(Weaving):將切面應用到目標對象從而創建一個新的代理對象的過程。這個過程可以發生在編譯期、類裝載期及運行期,當然不同的發生點有著不同的前提條件。譬如發生在編譯期的話,就要求有一個支持這種AOP實現的特殊編譯器;發生在類裝載期,就要求有一個支持AOP實現的特殊類裝載器;只有發生在運行期,則可直接通過Java語言的反射機制與動態代理機制來動態實現。
  •   生成代理對象的過程可以按照下圖理解:

      

      

      dojo/aspect模塊代碼主要分為兩部分:

    • advise方法,通過使用閉包跟鏈式模型來構造“通知”鏈。 "use strict";var undefined, nextId = 0;function advise(dispatcher, type, advice, receiveArguments){var previous = dispatcher[type];var around = type == "around";var signal;if(around){var advised = advice(function(){return previous.advice(this, arguments);});signal = {remove: function(){if(advised){advised = dispatcher = advice = null;}},advice: function(target, args){return advised ?advised.apply(target, args) : // called the advised functionprevious.advice(target, args); // cancelled, skip to next one }};}else{// create the remove handlersignal = {remove: function(){if(signal.advice){var previous = signal.previous;var next = signal.next;if(!next && !previous){delete dispatcher[type];}else{if(previous){previous.next = next;}else{dispatcher[type] = next;}if(next){next.previous = previous;}}// remove the advice to signal that this signal has been removeddispatcher = advice = signal.advice = null;}},id: nextId++,advice: advice,receiveArguments: receiveArguments};}if(previous && !around){if(type == "after"){// add the listener to the end of the list// note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bugwhile(previous.next && (previous = previous.next)){}previous.next = signal;signal.previous = previous;}else if(type == "before"){// add to beginningdispatcher[type] = signal;signal.next = previous;previous.previous = signal;}}else{// around or first one just replacesdispatcher[type] = signal;}return signal;} View Code
    • aspect方法,這個函數返回一個閉包。閉包的作用是將“通知”方法織入到目標函數中,java中運行時通過反射的方式來織入,而js中通過動態更改目標函數來實現織入過程,這時調用該方法可以使切面函數與業務邏輯同時進行。 function aspect(type){return function(target, methodName, advice, receiveArguments){var existing = target[methodName], dispatcher;if(!existing || existing.target != target){// no dispatcher in placetarget[methodName] = dispatcher = function(){var executionId = nextId;// before advicevar args = arguments;var before = dispatcher.before;while(before){args = before.advice.apply(this, args) || args;before = before.next;}// around adviceif(dispatcher.around){var results = dispatcher.around.advice(this, args);}// after advicevar after = dispatcher.after;while(after && after.id < executionId){if(after.receiveArguments){var newResults = after.advice.apply(this, args);// change the return value only if a new value was returnedresults = newResults === undefined ? results : newResults;}else{results = after.advice.call(this, results, args);}after = after.next;}return results;};if(existing){dispatcher.around = {advice: function(target, args){return existing.apply(target, args);}};}dispatcher.target = target;}var results = advise((dispatcher || existing), type, advice, receiveArguments);advice = null;return results;};} View Code

      ?

      注意:dojo的處理過程中并不生成代理對象,而是直接更改原有的對象的方法。

      關于aspect.after方法(before方法與其類似)的解釋請看這篇文章:Javascript事件機制兼容性解決方案;aspect.around的由來在這篇文章Javascript aop(面向切面編程)之around(環繞)里有其一步步的演化過程。

      本文給出aspect模塊調用后的示意圖:

      before與after函數:

      

      around函數:

      

    var advised = advice(function(){return previous.advice(this, arguments);});signal = {remove: function(){if(advised){advised = dispatcher = advice = null;}},advice: function(target, args){return advised ? //一旦調用remove,adviced變為空,便會跳過本次環繞通知,進入上一層的advice方法。advised.apply(target, args) : // called the advised functionprevious.advice(target, args); // cancelled, skip to next one }};

      可以看到around函數中借用閉包形成環繞函數鏈。這里調用remove方法后并沒有像before跟after中將通知方法徹底移除,注冊過的環繞方法仍然會存在內存中,所以這個方法無法移除環繞通知,僅僅是避免了在函數鏈中執行它而已。內存無法釋放,不建議使用太多。

    ?

    總結

    以上是生活随笔為你收集整理的dojo/aspect源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。