Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
preface
Record yourself learning design patterns, content from
JavaScript Design Patterns and Development Practices
Definition of proxy schema
The proxy pattern provides a proxy or placeholder for an object to control access to it
The key to the proxy pattern is to provide a proxy object to control access to an object when it is inconvenient or not necessary for the client to directly access it. After the proxy object does some processing on the request, it forwards the request to the local object
Xiao Ming chase MM
Xiao Ming likes girl A, Xiao Ming decided to send A bouquet of flowers to express his love, because Xiao Ming was too shy to send directly, Xiao Ming decided to let A friend B to complete the flowers instead of himself
Let’s look at the case without proxy mode
var Flower = function() {}
var xiaoming = {
sendFlower(target) {
const flower = new Flower()
target.receiveFlower(flower)
}
}
var A = {
receiveFlower(flower) {
console.log('Received flowers', flower)
}
}
// Next we introduce agent B
var B = {
receiveFlower(flower) {
A.receiveFlower(flower)
}
}
xiaoming.sendFlower(B)
Copy the code
Secure agents and virtual agents
Assuming that new Flower is expensive in the real world, and therefore expensive in the application world, we can delegate the new Flower operation to agent B, who will choose to execute the New Flower when AGENT A is in A good mood. This is another form of the agent mode, called virtual agent. Virtual proxies delay the creation of expensive objects until they are really needed. The following code
var B = {
receiveFlower(flower) {
A.listenGoodMood(() = > {
const flower = new Flower()
A.receiveFlower(flower)
})
}
}
Copy the code
The virtual proxy implements image preloading
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, Initial-scale =1.0"> <title>Document</title> </head> <body> <script> const myImage = (() => {var imgNode = document.createElement('img') document.body.appendChild(imgNode) return { setSrc(src) { imgNode.src = src } } })() var proxyImage = (() => { const img = new Image; img.onload = function() { myImage.setSrc(this.src) } return { setSrc(src) { myImage.setSrc('./assets/loading.gif') img.src = src } } })() proxyImage.setSrc('./assets/hashiqi.webp') </script> </body> </html>Copy the code
The virtual proxy merges HTTP requests
For example, in the following scenario: Every week, we need to write a weekly work report, which needs to be reviewed by the director. The director oversees 150 employees. If each of us sent the weekly report directly to the director, the director would spend the whole week looking at the weekly report.
Now we send the weekly report to our team leader, who acts as an agent to refine the weekly report of the team members into one copy and send it to the director in a lump sum. So the superintendent’s mailbox was clean
This example resonates well in the programming world, where perhaps the biggest overhead in Web development is the network request. If we are doing a file synchronization function, when we select a checkbox, its corresponding files will be synchronized to another secondary server
const synchronousFile = function(id) {
console.log('Start file synchronization with id:', + id)
}
var checkbox = document.getElementsByTagName('input')
for(let i = 0, c; c = checkbox[i++];) {
c.onclick = function() {
if (this.checked === true) {
synchronousFile(this.id)
}
}
}
Copy the code
When we checked the three checkboxes, we sent three requests to the server in turn to synchronize the files. Clicking on a checkbox is not a very complicated operation. It can be expected that such frequent network requests will incur considerable overhead.
The solution is to use a proxy function, proxySynchronousFile, to collect requests over a period of time and finally send them to the server once. For example, we wait two seconds before packaging and sending the ID of the file that needs to be synchronized within two seconds to the server. If the system is not very real-time demanding, the two-second delay will not bring too much side effect, but can greatly reduce the pressure on the server.
Application of virtual loading in lazy singletons
For example, with a plugin called miniconsole.log, press F2 to open the custom console
For example, enter miniconsole.log (1) on the console
This statement creates a div on the page and displays the log inside the div.
MiniConsole has about 1000 lines of code, so maybe we don’t want to load js files that big at first, because maybe not everyone needs to print logs. We want to start loading it only when necessary, such as when the user presses F2 to actively invoke the console.
Before miniconsole.js is loaded, in order to allow users to use the API normally, our solution is usually to use the miniConsole agent of a booth for users to use it in advance.
const miniConsole = (function() {
const cache = []
const handler = function(ev) {
if (ev.keyCode === 112) {
const script = document.createElement('script')
script.onload = function() {
for(let i = 0, fn; fn = cache[i++];) {
fn()
}
};
script.src = 'miniConsole.js'
document.getElementsByClassName('head') [0].appendChild(script)
document.body.removeEventListener('keydown', handler)
}
}
document.body.addEventListener('keydown', handler, false)
return {
log() {
const args = arguments
cache.push(() = > {
return miniConsole.apply(miniConsole, args)
})
}
}
})
miniConsole.log(11) // Start printing log
miniConsole = {
log() {
// The real code is omitted}}Copy the code
The caching proxy
The cache proxy can provide temporary storage for some expensive operation results, and the next operation can be directly returned if the parameters passed in are the same as the previous one
Example 1: Compute the product
const mult = function() {
let a = 1
for(let i = 0, l = arguments.length; i < l; i ++) {
a = a * arguments[i]
}
return a
}
console.log(mult(2.3)) / / 6
console.log(mult(2.3.4)) / / 24
// Now add the cache proxy function
const proxyMult = (function() {
const cache = {}
return function() {
const args = Array.prototype.join.call(arguments.', ')
if (args in cache) {
return cache[args]
}
return cache[args] = mult.apply(this.arguments)}}) ()console.log(proxyMult(1.2.3.4))
console.log(proxyMult(1.2.3.4))
Copy the code
Create an agent using higher-order functions
// Compute the product
const mult = function() {
let a = 1
for(let i = 0, l = arguments.length; i < l; i ++) {
a = a * arguments[i]
}
return a
}
// Calculate the sum
const plus = function() {
let a = 0
for(let i = 0, l = arguments.length; i < l; i++) {
a = a + arguments[i]
}
return a
}
// Create a factory for the cache proxy
const createProxyFactory = function(fn) {
const cache = {}
return function() {
const args = Array.prototype.join.call(arguments.', ')
if (args in cache) {
return cache[args]
}
console.log('calculated');
return cache[args] = fn.apply(this.arguments)}}const proxyMult = createProxyFactory(mult)
const proxyPlus = createProxyFactory(plus)
console.log(proxyMult(1.2.3.4));
console.log(proxyMult(1.2.3.4));
console.log(proxyPlus(1.2.3.4));
console.log(proxyPlus(1.2.3.4));
Copy the code
Other proxy modes
Firewall proxy: controls access to network resources and protects hosts from “bad guys”
Remote proxy: Provides a local proxy for an object in a different address space. In Java, a remote proxy can be an object in another virtual machine
Protected proxy: Used when objects should have different access rights
Smart reference proxy: Instead of simple Pointers, it performs additional operations on accessing objects, such as counting the number of times an object is referenced.
Copy-on-write agent: Typically used when copying a large object. The copy-on-write agent delays the copying process until the object is actually modified. Copy-on-write agent is a variant of virtual agent. DLL (dynamic link library in operating system) is the typical application scenario