The use of Promise

One of the most important and useful features in ES6 is the Promise, which is a solution for asynchronous programming. A very common scenario is probably network requests.

Basic grammar

Here we use a timer to simulate asynchronous events. The basic syntax for a Promise is as follows:

  1. The new Promise object is passed a callback function. When the callback function is executed, it is passed two arguments, resolve and reject, which are functions themselves
  2. The method in then() is executed when the request succeeds and resolve() is called
  3. When the request fails, reject() is called, executing the methods in catch()
  • One way to write, the chain way:

    new Promise((resolve, reject) = > {
      setTimeout(() = > {
        // Call resolve on success
        resolve('Hello World')
    
        // Reject is called on failure
        reject('error message')},1000)
    }).then((data) = > {
      console.log(data);
    }).catch((err) = > {
      console.log(err);
    })
    Copy the code
  • Alternatively, a new Promise is passed with three functions:

    new Promise((resolve, reject) = > {
      setTimeout(() = > {
        resolve('Hello Vuejs')
        reject('error message')},1000)
    }).then(data= > {
      console.log(data);
    }, err= > {
      console.log(err);
    })
    Copy the code

2. I Promise

When we have asynchronous operations in development, we can wrap a Promise around the asynchronous operations. There are three states after an asynchronous operation

  • pending: Wait state, such as a network request is in progress, or the timer is out of time.
  • fulfill: Satisfy the state when we actively call backresolveIs in this state and will be called back.then()
  • reject: rejected state when we actively callbackrejectIs in this state and will be called back.catch()

3. Promise chain call

1. Basic writing method

The second network request is sent by returning new Promise()

new Promise((resolve, reject) = > {

  // The code for the first network request
  setTimeout(() = > {
    resolve()
  }, 1000)

}).then(() = > {
  // The first time to get the result processing code
  console.log('111');

  // Send the network request again on the first processing
  return new Promise((resolve, reject) = > {

    // The code for the second network request
    setTimeout(() = > {
      resolve()
    }, 1000)
  })
}).then(() = > {

  // The code for the second processing
  console.log('222');

  return new Promise((resolve, reject) = > {

    // The code for the third network request
    setTimeout(() = > {
      resolve()
    })
  })
}).then(() = > {

  // The code for the third processing
  console.log('333');
})
Copy the code

2. Use static methods

  • Promise.resovle(): Wraps the data as a Promise object and calls back to the resolve() function internally
  • Promise.reject(): Wraps the data as a Promise object and calls the reject() function internally
new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('111')},1000)
}).then(res= > {
  // 1. Handle 10 lines of code by yourself
  console.log(res, '10 lines of processing code for the first layer');

  // 2. The result is processed for the first time
  return Promise.resolve(res + '222')
}).then(res= > {
  console.log(res, 'Layer 2 10 lines of processing code');

  return Promise.resolve(res + '333')
}).then(res= > {
  console.log(res, 'layer 3 10 lines of processing code');
})
Copy the code

3. Go straight back

  • usereturn dataTo replace thereturn Promise.resovle(data)
  • usethrow dataTo replace thereturn Promise.reject(data)
new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('111')},1000)
}).then(res= > {
  // 1. Handle 10 lines of code by yourself
  console.log(res, '10 lines of processing code for the first layer');

  // Here is a direct return string, equivalent to promise.resovle (res + '111')
  return res + '111';
}).then(res= > {
  console.log(res, 'Layer 2 10 lines of processing code');

  // The first processing of the result (error)
  // Equivalent to return promise.reject ('error message')
  throw 'error message'
}).then(res= > {
  console.log(res, 'layer 3 10 lines of processing code');
}).catch(err= > {
  console.log(err);
})
Copy the code

4. Promise.all

Promse.all is useful when handling multiple asynchronous processes. Then is executed only after all requests have been successful, such as waiting for data from two or more asynchronous operations to come back.

Success returns an array; On failure, return the value of the first rejected failure state.

Promise.all([
  new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve('111')},2000)}),new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve('222')},1000)
  })
]).then(results= > {
  console.log(results);	/ / / '111', '222'
})
Copy the code

5. Promise.race

Race ([p1, P2, p3]) returns a result that is fast, regardless of whether the result itself is a success or a failure.

2. Use of Axios

Official website: www.axios-js.com/ Official document: www.axios-js.com/zh-cn/docs/

Axios is an HTTP library based on promises (used in ES6 to handle async) used in browsers and node.js.

1. Install and introduce

  • Installation:

    npm install axios --save
    Copy the code
  • The introduction of axios:

    import axios from 'axios'
    Copy the code

2. Send a request

Axios supports several ways to request and call (the contents in brackets can be omitted) :

axios(config)

// Request the alias of the method
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
Copy the code

== Note == : When using an alias method, the URL, method, and data properties do not have to be specified in the configuration.

3. The config configuration

Some common configurations are:

  • Url: The server URL of the request

  • Method: Method used to request the server. If no method is specified, get is used by default

  • BaseURL: baseURL is automatically added before the URL

  • The data/params: The difference is that data will PUT == data in the request body ==, and params will PUT == data in the URL ==. So when method is POST/PUT/PATCH, use data, and use params for the rest

    == Note == : When passing values using data, use qs.stringify() to serialize the object to the URL form, otherwise the background will not receive the value. See chapter 3, Section 2

  • Timeout: indicates the timeout period

Config configuration (from official document: stamp here) :

{
   // 'url' is the server URL used for the request
  url: '/user',

  // 'method' is the method used to create the request
  method: 'get', // default

  // 'baseURL' will automatically precede 'url' unless 'url' is an absolute URL.
  // It is easy to pass relative URLS for axios instance methods by setting a 'baseURL'
  baseURL: 'https://some-domain.com/api/',

  // 'transformRequest' allows you to modify the request data before sending it to the server
  // Can only be used in 'PUT', 'POST' and 'PATCH' request methods
  // Functions in the following array must return a string, or an ArrayBuffer, or a Stream
  transformRequest: [function (data, headers) {
    // Convert data arbitrarilyreturn data; }].// 'transformResponse' allows the response data to be modified before being passed to the THEN /catch
  transformResponse: [function (data) {
    // Convert data arbitrarilyreturn data; }].// 'headers' is the custom request header to be sent
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // 'params' is the URL parameter to be sent with the request
  // Must be a plain Object or URLSearchParams object
  params: {
    ID: 12345
  },

   // 'paramsSerializer' is a function responsible for 'params' serialization
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // 'data' is the data sent as the body of the request
  // Only applies to these request methods 'PUT', 'POST', and 'PATCH'
  // When 'transformRequest' is not set, it must be one of the following types:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - browser only: FormData, File, Blob
  // -node exclusive: Stream
  data: {
    firstName: 'Fred'
  },

  // 'timeout' specifies the number of milliseconds for the request to timeout (0 means no timeout)
  // If the call cost exceeds' timeout ', the request will be interrupted
  timeout: 1000.// 'withCredentials' indicates whether to use credentials in cross-domain requests
  withCredentials: false.// default

  // Adapter allows custom processing of requests to make testing easier
  // Return a promise and apply a valid response (see [Response Docs](#response-api)).
  adapter: function (config) {
    / *... * /
  },

 // 'auth' indicates that HTTP basic authentication should be used and the credentials provided
  // This will set an Authorization header, overriding any existing custom Authorization headers that are set using headers
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

   // 'responseType' indicates the data type of the server response, which can be 'arrayBuffer ', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // default

  // `responseEncoding` indicates encoding to use for decoding responses
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // default

   // 'xsrfCookieName' is the name of the cookie used as the value of the XSRF token
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

   // 'onUploadProgress' allows processing progress events for uploads
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // 'onDownloadProgress' allows processing progress events for downloads
  onDownloadProgress: function (progressEvent) {
    // Handling of native progress events
  },

   // 'maxContentLength' defines the maximum size of the response content allowed
  maxContentLength: 2000.// 'validateStatus' defines a resolve or reject Promise for a given HTTP response status code. If 'validateStatus' returns' true' (or is set to 'null' or 'undefined'), the promise will be resolved; Otherwise, the promise will be rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // 'maxRedirects' directs to the maximum number of redirects to follow in node.js
  // If set to 0, no redirection will be followed
  maxRedirects: 5.// default

  // `socketPath` defines a UNIX Socket to be used in node.js.
  // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
  // Only either `socketPath` or `proxy` can be specified.
  // If both are specified, `socketPath` is used.
  socketPath: null.// default

  // 'httpAgent' and 'httpsAgent' are used in Node.js to define custom proxies to use when executing HTTP and HTTPS, respectively. Allows options to be configured like this:
  KeepAlive 'is not enabled by default
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' defines the host name and port of the proxy server
  // 'auth' indicates that HTTP basic authentication should be used for the connection proxy and provide credentials
  // This will set a 'proxy-authorization' header, overriding the existing custom 'proxy-authorization' header set by using 'header'.
  proxy: {
    host: '127.0. 01.',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  CancelToken specifies the cancel token used to cancel the request
  // (See "Cancellation" for more information)
  cancelToken: new CancelToken(function (cancel) {
  })
}
Copy the code

4. Response structure

The response to a request contains the following information

{
  // 'data' Response provided by the server
  data: {},

  // 'status' indicates the HTTP status code from the server response
  status: 200.// 'statusText' HTTP status information from the server response
  statusText: 'OK'.// 'headers' Indicates the server response header
  headers: {},

   // 'config' is the configuration information provided for the request
  config: {},
 // 'request'
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}}Copy the code

5. Concurrent requests

With AXIos.all (), you can put an array of multiple requests, similar to promise.all.

The result returned by axios.all([]) is an array that can be expanded to res1,res2 using axios.spread

axios.all([axios({
  url: 'http://123.207.32.32:8000/home/multidata'
}), axios({
  url: 'http://123.207.32.32:8000/home/data'.params: {
    type: 'sell'.page: 5
  }
})]).then(results= > {
  console.log(results);
  console.log(results[0]);
})
Copy the code

6. Global configuration

Many parameters may be fixed in development. At this point we can take advantage of axiOX’s global configuration

Axios. Defaults. BaseURL = '123.20732.32.:8000'axios. Defaults. Headers. Post [' the content-type] =' application/x - WWW - form - urlencoded ";Copy the code

6. Create an instance

When we import objects from the AXIos module, the default instance is used. When you set some default configurations for the instance, these configurations are fixed. However, in future development, some configurations may be different. For example, some requests require a specific baseURL or timeout or content-type.

At this point, we can create a new instance and pass in the configuration information that belongs to that instance

  • Create an instance:
axios.create([config])
Copy the code
  • Such as:

    const instance = axios.create({
      baseURL: 'https://some-domain.com/api/'.timeout: 1000.headers: {'X-Custom-Header': 'foobar'}});Copy the code

7. Instance methods

Here are the available instance methods. The specified configuration is merged with the configuration of the instance.

axios#request(config)
axios#get(url[, config])
axios#delete(url[, config])
axios#head(url[, config])
axios#options(url[, config])
axios#post(url[, data[, config]])
axios#put(url[, data[, config]])
axios#patch(url[, data[, config]])
Copy the code

8. The interceptor

Axios provides interceptors that we use to process each request after we send it or receive it.

Request interceptor

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // What to do before sending the request
    return config;
  }, function (error) {
    // What to do about the request error
    return Promise.reject(error);
  });

// Add a request interceptor to the instance
const instance = axios.create();
instance.interceptors.request.use(function () {/* Same as above */});
Copy the code

Function before sending a request

  1. When a network request is sent, add a loading component to the page as an animation
  2. Some requests require that the user must login. If the user does not have a token, the login page is displayed
  3. Sequentially instantiate the parameters of the request

Error interception application in request interception:

  • If the request times out, the page can be redirected to an error page

Response interceptor

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // What to do with the response data
    return response;
  }, function (error) {
    // Do something about the response error
    return Promise.reject(error);
  });

// Add a response interceptor for the instance
const instance = axios.create();
instance.interceptors.response.use(function () {/* Same as above */});
Copy the code

The successful interception of the response mainly involves filtering the data.

In the interception of the response failure, you can determine the error code based on the status and go to different error pages.

9. Axios encapsulation

This is a simple encapsulation of Axios

import axios from 'axios'

export function request(config) {
  // 1. Create an instance of Axios
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000'.timeout: 5000
  })

  // 2. The Axios interceptor
  // 2.1. The role of request interception
  instance.interceptors.request.use(config= > {
    // console.log(config);
    // 1. For example, some information in the config file does not meet the server requirements

    // 2. For example, every time you send a network request, you want to display a request icon in the interface

    // 3. Certain network requests (such as login (token)) must carry some special information
    return config
  }, err= > {
    // console.log(err);
  })

  // 2.2. Response interception
  instance.interceptors.response.use(res= > {
    // console.log(res);
    return res.data
  }, err= > {
    console.log(err);
  })

  // 3. Send a real network request
  return instance(config)
}
Copy the code

The pit Axios stepped in

1. Encoding problem when the passed parameter is an array

Introduction:

import axios from 'axios'
import qs from 'qs'
Copy the code
  • Get/DELETE request mode The solution is as follows

    axios.get(url, {
        params: {
         ids: [1.2.3].type: 1
        },
        paramsSerializer: params= > {
          return qs.stringify(params, { indices: false })
        }})
    
    axios.delete(url, {
         params: {
         ids: [1.2.3].type: 1
        },
        paramsSerializer: params= > {
          return qs.stringify(params, { indices: false})}})Copy the code
  • In POST/PUT mode, the solution is as follows

    axios.post(url, qs.stringify(
        params: {
          ids: [1.2.3].type: 1
        }, { indices: false }))
    
     axios.put(url, qs.stringify(
       params: {
         ids: [1.2.3].type: 1
       }, { indices: false }))
    Copy the code
  • There are four ways to convert:

    qs.stringify({ids: [1.2.3] {},indices: false })
     Ids =1& IDS =2& IDS =3
    qs.stringify({ids: [1.2.3] {},arrayFormat: ‘indices‘})
     // Form: ids[0]=1&aids1 =2&ids[2]=3
    qs.stringify({ids: [1.2.3] {},arrayFormat: ‘brackets‘})
     // Form: ids[]=1&ids[]=2&ids[]=3
    qs.stringify({ids: [1.2.3] {},arrayFormat: ‘repeat‘}) 
    Ids =1& IDS =2& IDS =3
    Copy the code

Reference: Axios passes array parameters to climb pit summary

2. Problems with passing parameters using data (using QS)

When sending a POST/PUT request using Axios, the parameters are placed in the body of the request, so we pass the values using data:

axios({
    method: 'post'.url: '/api/lockServer/search'.data: {
        "username": "test"."psd": "123456"}})Copy the code

But when the parameter is received in the background (Tomact + SpringBoot + SpringMVC), it is not received.

Solution:

  1. withqs.stringify()Serialize the object into a URL,qsaxiosIt comes with it, so you can just introduce it
  2. Set in the request headerContent-Typeapplication/x-www-form-urlencoded(Can also be measured without)
import qs from 'qs'
let data = {
    "username": "test"."psd": "123456"
}
 
axios({
    //headers: {
    // 'Content-Type': 'application/x-www-form-urlencoded'
    / /},
    method: 'post'.url: '/api/lockServer/search'.data: qs.stringify(data)
})
Copy the code

axios qs