preface

Delivery address:

The factory model of the front-end design pattern

In the last article, we briefly learned about the application of engineering mode in front-end development through pet shop. So continuing with our link to design patterns 23, let’s look at the proxy pattern in the front end

The proxy pattern

What is the agency model?

Definition of the proxy pattern: the proxy pattern provides a proxy object to an object, and the proxy object controls the reference to the original object. Generally speaking, the agent mode is the common intermediary in our life.

Why use the proxy pattern

Mediation isolation: In cases where a client class does not want or cannot refer directly to a delegate object, a proxy object can mediate between a client class and a delegate object, characterized by the fact that the proxy class and the delegate class implement the same interface.

Open closed principle, adding functionality: In addition to the proxy class acting as a mediator between the client class and the delegate class, we can extend the functionality of the delegate class by adding additional functionality to the proxy class. In this way, we only need to modify the proxy class without modifying the delegate class, in line with the open closed principle of the code design. The proxy class is mainly responsible for preprocessing messages, filtering messages, forwarding messages to the delegate class, and processing the returned results after the event. The proxy class itself does not actually implement the service, but rather provides a specific service by calling the relevant methods of the delegate class. The real business function is still implemented by the delegate class, but some common services can be added before and after the business function is performed. For example, if we want to add caching, logging, and other functions to the project, we can use the proxy class to do so without having to open the wrapped delegate class

Take a chestnut

Since we mention the intermediary, we have to say that in our daily life, there are all kinds of intermediary, such as real estate agent, 4S shop, ticket office and so on.

In fact, the pet store in the previous article is also a kind of intermediary, because all the pet sources are not directly generated in the store, some of them come from the wild, some from the farm, etc.

Since we are going to expand our business, we need intermediaries to help us expand our business at this time.

class headPet { // The main pet store provides the most basic service of selling and buying back pets
  sellPet(name) { // Sell pets
    console.log('A pet for Sale', name)
  }
  desert(name) { // Abandoning pets
 console.log('Abandoning a pet', name)  } }  class subPet extends headPet { // Pet branch, we provide matching service, in order to better sell pets  constructor() {  super(a) }  sell(name) { // Sell pets  this.sellPet(name)  }  sellPetFood(name) { // Buy pet food and give pet away  console.log('With a big wave of food.')  this.sellPet(name)  }  sellPetCage(name) { // Buy pet cages and give pets away  console.log('With a big cage')  this.sellPet(name)  } }  const subPet1 = new subPet() subPet1.sell('tom') subPet1.sellPetFood('tom') subPet1.sellPetCage('tom') Copy the code

Simple program from above, we can see that, as a branch, actually sell pet, also with all kinds of services, such as pet food, pet cage, so that we better to sell pet, finally we still call the head office of the service, but its also provides additional services, make our business to expand, this is a branch gives rise to the ability of head office.

The project of actual combat

Next, we use the idea of the agent pattern to put it into practice on a project.

Proxy request – Read local cache

function ajax(params) { // The actual method of sending the request
  console.log('Send request${params}`)
  return params + Math.random()
}

const storage = new Map(a); function cache(params) { // Cache mode  if (storage.has(params)) {  return storage.get(params)  }  const value = ajax(params)  storage.set(params, value)  return value }  function proxyAjax(params) { // Proxy ajax requests  return cache(params) }  console.log(proxyAjax(1)) // Send a request with parameter 1 console.log(proxyAjax(1)) // Send a request with the same parameter as 1. The cache reads the request from the cache, so it returns the result without calling the Ajax method console.log(proxyAjax(2)) // Send a request with parameter 2, which is not read from the cache, and call the Ajax method directly from the background request Copy the code

As you can see from the above code, we have a layer of Ajax request methods and add a cache layer, which helps us to save some time and resources by not calling the HTTP request with the same parameters.

It is recommended that in the actual use of the project, judge according to the service as much as possible. Do not cache all requests arbitrarily. Generally, cache GET requests or data requests whose data is not easy to change.

In addition, this feature can be extended to include the concept of cache time, so that requests with the same parameters can be read directly from the cache for a certain amount of time.

Buried point function – proxy global FETCH

const oldFetch = window.fetch;

function newFetch(url, init) { // Re-fetch method, proxy fetch itself function, add buried point function
  const { method = 'GET', body } = init || {};
  const fetchObj = {
 url: url,  method: method,  body: body,  start: performance.now(),  }   ajaxEventTrigger.call(fetchObj, AJAX_START); // Customize the buried point listening method   return oldFetch.apply(this.arguments).then(function (response) {  fetchObj.end = performance.now();  if (response.ok) {  ajaxEventTrigger.call(fetchObj, AJAX_END)  } else {  ajaxEventTrigger.call(fetchObj, AJAX_ERROR)  }  return response  }).catch(function (error) {  fetchObj.end = performance.now();  fetchObj.error = error  ajaxEventTrigger.call(fetchObj, AJAX_ERROR);  throw error  }) }  window.fetch = newFetch; Copy the code

This example overwrites the native FETCH method and uses a similar approach to the proxy pattern, the global FETCH method, to perform request burying

With this example, you can rewrite the life cycle function and other functions of the small program to add a custom buried point event, which will be tested in the next buried point performance blog

Cache proxy – Handles cache times

class Storage {

  constructor(props) { // Initialize the cache method based on the type and cache time
    const { type, time } = props
    this.type = type
 this.time = time  this.storageType = {  local: 'localStorage'. session: 'sessionStorage'  }  }   setItem(key, value) { // Proxy the native cache method and add cache time  window[this.storageType[this.type]].setItem(key, JSON.stringify({  value,  time: new Date().getTime()  }));  }   getItem(key) { // The proxy obtains the cache method native and determines whether the data is expired according to the cache time  try {  const { time, value } = JSON.parse(window[this.storageType[this.type]].getItem(key));  const now = new Date().getTime()  if (now > time + this.time) {  window[this.storageType[this.type]].removeItem(key);  return null  } else {  return value  }  } catch (e) {  return null  }  } }  const local = new Storage({ type: 'local'.time: 30000 }) // Initialize localStorage and add 5 minutes cache time const session = new Storage({ type: 'session'.time: 30000 }) // Initialize sessionStorage and add 5 minutes cache time local.setItem(1.2) local.getItem(1) session.setItem(3.4) session.getItem(3)  Copy the code

This approach can be extended to differentiate by type of storage, for example

Additional information

Complete demo address: project actual demo, like friends can star, the follow-up will be based on the launch of the design mode blog, gradually continue to expand this project.

Manual dog head town building

This article was typeset using MDNICE