The Proxy pattern uses one object as the interface for another object
- It sits between users or clients of the object and the object itself
- client makes request to proxy, proxy makes request to object
- clients may or may not know if they are using a proxy
- the proxy controls access to the original object (acts as a guardian)
- often used for performance reasons
- if the object needs to make expensive HTTP requests (or others), we make batch requests in the proxy in order to send fewer requests to the object
- proxy can include cashe to store requests for further use
- Proxies can also be used to delay the instantiation of a slow or resourse intensive object, when it is better for performance to delay
- we might need the object at some time
- this is called a Just-In-Time Proxy, which is what we will be making
- first time that proxy invokes methods of objects will be slow, but subsequent times will be fast as object has already been initialized
- great thing about this is even if client initializes proxy, we may not need the slow object unless a method on the slowObject is needed
Step 1 – Page: slowObject.js
// JavaScript Document
define(function () {
'use strict';
var SlowObject = function () { //set up slowObject
this.someMethod = function () {
console.log('some method on the slow object was invoked'); //use method to log a statement
};
};
return {
init: function () { //add artificial initialization delay with for loop
for (var x = 0, max = 1000; x < max; x++) { //for loop iterates 1000 times
console.log('slowness...');
}
return new SlowObject();//once loop finishes, returns new instance of slowObject
}
};
});
Step 2 – Page: slowObjectProxy.js
// JavaScript Document
define(function (require) {//use require function
'use strict';
var SlowObjectProxy, slowObjectInstance, //initialize variables
slowObject = require('proxy/slowObject');
SlowObjectProxy = function () { //set up constructor for proxy object
this.someMethod = function () { //add method that matches the slowObject method
var interval; //add the new variable
if (!slowObjectInstance) { //check if the slowObject has been initialized previously
slowObjectInstance = slowObject.init(); //if return is falsy, we haven't initialized yet, so we use init method to initialize
} else { //if it has been initialized
slowObjectInstance.someMethod(); //we invoke the same method on the slowObject
}
interval = window.setInterval(invokeMethodWhenExists, 100); //set this up to poll the object and wait for initizialization.
function invokeMethodWhenExists() { //the above interval will invoke this method every 100 seconds in order to check if slowObject has been created yet
if (slowObjectInstance) { //we check the slowObjectIstance variable, and if truthy
console.log('proxying some method'); //use a log to know the proxy is working as expected
window.clearInterval(interval); //clear the interval to stop the loop
slowObjectInstance.someMethod(); //then invoke the method on the slow object
}
}
};
};
return {
init: function () {
return new SlowObjectProxy();
}
};
});
Step 3 – Page: init.js
define(function(require) {
'use strict';
return {
init: function() {
var myProxy, //set up variables
slowObjectProxy = require('proxy/slowObjectProxy');
myProxy = slowObjectProxy.init(); //initialize the slowObject, which delayed by the interval
myProxy.someMethod();
}
};
});
Step 4 – Page: main.js
// JavaScript Document
require (
['proxy/init'],
function ( proxy) {
'use strict';
var examples = {
proxy:proxy
};
window.runExample = function (example) {
examples[example].init();
};
}
);
Conclusion
The proxy pattern can be used to control access another object, either because it takes a long time to initialize or it is an expensive operation to carry out
- proxy exposes same interface as the original object and sits between client and object, intercepting requests and handling on behalf of the object.