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