dojo/aspect源码解析
生活随笔
收集整理的這篇文章主要介紹了
dojo/aspect源码解析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
dojo/aspect模塊是dojo框架中對于AOP的實現。關于AOP的詳細解釋請讀者另行查看其它資料,這里簡單復習一下AOP中的基本概念:
生成代理對象的過程可以按照下圖理解:
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源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android -- DragDrop
- 下一篇: 美国域名总量跌至7971万:4月上旬降幅