This is the 12th day of my participation in Gwen Challenge

With the development of front-end asynchracy, XHR’s coupling approach to writing is not conducive to front-end asynchronous Promise callbacks. The fetch API was originally proposed in SW(ServiceWorkers), but I decided to mount it under the Window object. In this way, in the normal communication of the front end, we can also call directly.

compatibility

As a common API in the future, take a look at its compatibility.

On PC, FF, Opera and Chrome compare fashion. Mobile, and it basically doesn’t work. Of course, there is an official polyfill ready to use.

Browser versions such as Chrome 45+, Opera 44+, Firefox 51+ and IE Edge are starting to support the Fetch API. Mobile browsers are also gaining support.

We can determine whether the browser supports the FETCH API by checking the capabilities of window.fetch. Github officially launched a Polyfill library of Fetch API, which can make more browsers experience the convenient development experience of Fetch API in advance.

Generally, the use of a new feature needs to judge compatibility, which can be referred to Modernizr library.

The basic use

Fetch is ajax + Promise. It works in much the same way as $.ajax() provided by jquery.

fetch('http://wthrcdn.etouch.cn/weather_mini?citykey=101010100')
    .then(function (response) {
            if(response.status ! = =200) {
                console.log('return the response code${response.status}`)
                return
            }

            // Get the returned data
            response.json().then(function (data) {
                document.body.innerText = data.toString()
                console.log(data)
            })
        }
    ).catch(function (err) {
    console.log('Fetch Error: -S', err)
})
Copy the code

Then and catch are two methods that come with promises, so I won’t go into them here. So let’s see what JSON does.

Because the returned data includes not only the background Text, but also some Headers. So the RES returned from the THEN method is not really what we want in our business. Just like we returned data in XHR, we’re going to end up with the responseText data. What the json() method actually does is call json.parse () to process the data and return a new Promise. Take a look at polyfill’s source code.

this.json = function() {
    return this.text().then(JSON.parse)
}
Copy the code

Note here that response/ Request in fetch are stream objects.

Fetch transfer format

The demo above is a request for a get Method. Of course, there are other HTTP methods, PUT, DELETE, POST, PATCH, etc. Here, let’s just say a POST, but the basic format of the other methods is similar.

fetch("http://www.example.org/submit.php", {
  method: "POST".headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  body: "this is a post Msg"
}).then(function(res) {
  if (res.ok) {
    // doSth
  } else if (res.status == 401) {
    // doSth}});Copy the code

It doesn’t look like fetch is much different from $. Ajax… But… Fetch has a lot of content. Fetching is actually a combination of Request,Headers, and Response. However, these 3 can only be used in SW. I’m just going to do the principle here. I’m just going to do the parameters.

Headers operation

The Headers operation is nothing more than CRUD, so I won’t go into details here.

var content = "Hello World";
var reqHeaders = new Headers();
reqHeaders.append("Content-Type"."text/plain"
reqHeaders.append("Content-Length", content.length.toString());
reqHeaders.append("X-Custom-Header"."Custom header");
Copy the code

Of course, you can also use the literal form:

reqHeaders = new Headers({
  "Content-Type": "text/plain"."Content-Length": content.length.toString(),
  "X-Custom-Header": "Custom header"});Copy the code

Next, the content of the head is related to detection.

console.log(reqHeaders.has("Content-Type")); // true
console.log(reqHeaders.has("Set-Cookie")); // false
reqHeaders.set("Content-Type"."text/html");
reqHeaders.append("X-Custom-Header"."Add custom header");
 
console.log(reqHeaders.get("Content-Length")); / / 11
console.log(reqHeaders.getAll("X-Custom-Header")); // [" custom header ", "new custom header "]
 
reqHeaders.delete("X-Custom-Header");
console.log(reqHeaders.getAll("X-Custom-Header")); / / []
Copy the code

However, for security reasons, it is sometimes necessary to restrict headers when working with multiple people or managing subsections. You can set the policy of Headers by using the guard property. Guard can be immutable, request, request-no-cors, response, or None. We’re not going to explore all of them here, just look at the request option. After setting request, if you set the Header to forbidden Header name (which is automatically set by the browser), the operation will not be successful. Accept-charset, accept-encoding, access-Control-request-headers, etc.

In contrast to fetch, there is no way to set the Headers guard, so this can only be used in SW.

The Request operation

The basic usage of Request is similar to fetch.

var uploadReq = new Request("/uploadImage", {
  method: "POST".headers: {
    "Content-Type": "image/png",},body: "image data"
});

fetch("/uploadImage", {
  method: "POST".headers: {
    "Content-Type": "image/png",},body: "image data"
});
Copy the code

So what does fetch do? The key point is that fetch is actually a container for Request/Reponse. Request/Response is just two pieces of metadata, and fetch is just the actual operation. So, in order to achieve higher reusability, we can instantiate ajax requests into concrete objects.

var getName = newRequest(... , {/ /... });
var getGender = newRequest(... , {/ /... });

// Send the request
fetch(getName)
.then((res) = >{});

fetch(getGender)
.then((res) = >{});
Copy the code

In the browser, all requests are subject to cross-domain and non-cross-domain issues. Fetch is no exception. For cross-domain requests, the main impact is still reflected in Response, the fetch Request, which has little impact. However, we need to set the mode property at the fetch to indicate that this is a cross-domain request.

fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors'})  
  .then(function(response) {  
    return response.text();  
  }) 
Copy the code

Common mode attribute values are:

  • Same-origin: Indicates that only the same domain is requested. If you are making cross-domain requests in this mode, an error will be reported.
  • No-cors: indicates a normal network request. This request should be valid for access-Control-allow-origin. It’s used to handle requests for script, image, etc. It is the default value of mode.
  • Cors: Used to send cross-domain requests. This is required when sending requests.
  • Cers-with-force-preflight: This preflight is specially supported by XHR2. It sends an additional request to the server to check the validity of this request.

In addition, there is cross-domain content about cookies. In XHR2, we see that the withCredentials attribute is used to set whether to send local cookies to servers in different domains during cross-domain operations. Omit anything. In fetch, the credentials attribute is used. The usual values are:

  • Omit: do not omit cookies when sending requests. Default value.
  • Same-origin: Cookies are sent with same-domain requests.
  • Include: Cookies are included whenever a request is sent.

So, if you want to send Ajax with cookies, you need to use Same-Origin, and if you want to send cookies across domains, you need include.

// Cross-domain request
fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors'.credentials:'include'})  
  .then(function(response) {  
    return response.text();  
  }) 
Copy the code

The Response operation

Response should count the object closest to fetch. Response is actually the argument returned by the fetch callback. There are four commonly used attributes in Response: status, statusText, OK and type.

  • Status: returned status code 100-500 +
  • StatusText: Returns the meaning of the status code. For example, return “OK “.
  • Ok: checks whether the status is between 200 and 299.
  • Type: indicates whether the request is cross-domain or whether an error occurs. The value can be Basic, CORS, default, Error, or Opaque.
fetch('https://www.villainhr.com/cors-enabled/some.json', {mode: 'cors'.credentials:'include'})  
  .then(function(response) {  
    // ...
  }) 
Copy the code

Here, let’s focus on some of the properties mounted on Type.

  • Basic: Local communication category. The response header can be accessed normally (except for the set-cookie header).
  • Cors: cross-domain communication category. Generally, only the following headers can be accessed:
  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma
  • Error: indicates the network error type.
  • Opaque: Failed to understand the category. Emitted when a cross-domain request is sent using no-CORS.

In addition, several common methods are mounted on response: text() and json().

  • Text (): mainly used to process string data returned by the server.
  • Josn (): is used to process json data returned by the server.

It’s all a streaming API.

fetch('https://www.villainhr.com/cors-enabled/some.json')  
  .then(function(res) {  
    res.text().then((text) = >{... }) res.json().then((obj) = >{...})
  }) 
Copy the code

The body to deal with

When we request data through Ajax, we might get arrayBuffers, BLObs/files, strings, FormData, and so on. And, when you send something like this:

var form = new FormData(document.getElementById('login-form'));
fetch("/login", {
  method: "POST".body: form
})
Copy the code

Fetch automatically sets the associated content-Type header. Alternatively, if we can manually generate a response stream (for later purposes).

var res = new Response(new File(["chunk"."chunk"]."archive.zip", {type: "application/zip" }));

Copy the code

The processing of flow

Because req/ RES exist as streams, the body of a REq/RES can only be used once. If a file is read from the cache to the hard disk, the original file has disappeared. We can check whether the object is already used by bodyUsed.

var res = new Response("one time use");
console.log(res.bodyUsed); // false
res.text().then(function(v) {
  console.log(res.bodyUsed); // true
});
console.log(res.bodyUsed); // true
 
res.text().catch(function(e) {
  console.log("Tried to read already consumed Response");
});
Copy the code

The main reason for doing this is to enable the Web to better handle video related data in the future. What if I sometimes want to use it more than once? For example, in our Service Worker, we use the Caches API to cache the response, and then LATER I have to return the response to the browser, so the response stream is used twice. Here, as with normal stream operations, a copy of the stream is cloned using:

addEventListener('fetch'.function(evt) {
  var sheep = new Response("Dolly");
  console.log(sheep.bodyUsed); // false
  var clone = sheep.clone();
  console.log(clone.bodyUsed); // false
 
  clone.text();
  console.log(sheep.bodyUsed); // false
  console.log(clone.bodyUsed); // true
 
  evt.respondWith(cache.add(sheep.clone()).then(function(e) {
    return sheep;
  });
});
Copy the code

conclusion

While the Fecth API is easy to use and semantic, it has its limitations at this stage. The Fetch API is based on Promises. Since promises do not have a mechanism for handling timeouts, they cannot handle interrupts after a request times out and the ability to read progress in a native way. However, it is believed that in the future to support streaming, the Fetch API will eventually provide the ability to interrupt the execution of reading resources and provide an API to read progress.

The above! Last rule, post my blog, welcome to follow

Please pay attention to the official number: Full stack flying Squadron