Hướng dẫn và ví dụ Javascript Fetch API

1- Tổng quan về Fetch API

Rất thường xuyên trong lập trình Javascript bạn cần lấy dữ liệu từ một URL. Bạn có thể nghĩ đến XMLHttpRequest API, nó thực sự là một API giúp bạn làm được điều bạn muốn, nhưng nó không thân thiện, bạn phải viết code khá dài để đạt được mục đích. Sử dụng jQuery là một ý tưởng hay, cú pháp jQuery.ajax(..) ngắn gọn và dễ hiểu, nhưng bạn phải thêm thư viện jQuery vào ứng dụng của bạn.

ES6 được giới thiệu vào tháng 6 năm 2015, có rất nhiều tính năng mới được đưa vào trong đó có Promise. Và Fetch API là một tiêu chuẩn mới để tạo một yêu cầu (request) gửi đến server và nhận về một dữ liệu, mục đích của nó giống với XMLHttpRequest, sự khác biệt là Fetch API được viết dựa trên khái niệm Promise.

Sẽ dễ dàng hơn nếu bạn có khái niệm về Promise trước khi tiếp tục với bài học này, và tôi khuyến nghị bạn tham khảo bài viết dưới đây của tôi, nó hoàn toàn dễ hiểu với tất cả mọi người.

  • Hướng dẫn và ví dụ ECMAScript Promise, Async Await

Fetch API xây dựng một hàm fetch(url,options) dùng để lấy dữ liệu từ một URL, hàm này trả về một Promise, nó giống như sau:


function fetch(url, options)  {

    // A Promise
    var aPromise = new Promise (
        function (resolve, reject) {

            if (allthingOK) {
               // ...
               var respone = ...;

               resolve(response);
            } else {
                var error = new Error('Error Cause');
                reject(error);
            }

        }
    );

    return aPromise;
}

Và bạn có thể sử dụng Fetch API một cách khá đơn giản, chỉ cần gọi hàm fetch(url,options) và nhận được một lời hứa giải quyết (resolve) đối tượng response.


var url = "http://example.com/file";
var options = { method : 'GET', .... };

var aPromise = fetch(url, options);

aPromise
    .then(function(response) {
        
    })
    .catch(function(error) {
        
    });

var aPromise = fetch(url, {
    method: "GET", // POST, PUT, DELETE, etc.
    headers: {
        "Content-Type": "text/plain;charset=UTF-8" // for a string body, depends on body
    },
    body: undefined // string, FormData, Blob, BufferSource, or URLSearchParams
    referrer: "about:client", // "" for no-referrer, or an url from the current origin
    referrerPolicy: "no-referrer-when-downgrade", // no-referrer, origin, same-origin...
    mode: "cors", // same-origin, no-cors
    credentials: "same-origin", // omit, include
    cache: "default", // no-store, reload, no-cache, force-cache, or only-if-cached
    redirect: "follow", // manual, error
    integrity: "", // a hash, like "sha256-abcdef1234567890"
    keepalive: false, // true
    signal: undefined, // AbortController to abort request
    window: window // null
});

2- Get Text – response.text()

Sử dụng Fetch API để gửi một yêu cầu và nhận về một văn bản là một nhiệm vụ đơn giản và dễ hiểu nhất.



This is a simple text data.
 

Hàm fetch(..) trả về một lời hứa giải quyết (resolve) một đối tượng response. Vì vậy để gửi một yêu cầu (request) để lấy về một dữ liệu văn bản bạn cần thực hiện bước 1 như sau:

get-text-example.js ( Step 1 )


// A URL returns TEXT data.
var url = "https://ex1.o7planning.com/_testdatas_/simple-text-data.txt";


function doGetTEXT()  {

  // Call fetch(url) with default options.
  // It returns a Promise object (Resolve response object)
  var aPromise = fetch(url);

  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        // Network Error!
        console.log(error);
    });

}

Phương thức response.text() trả về một lời hứa giải quyết một đối tượng text, vì vậy bạn có thể viết tiếp code cho ví dụ này như sau:

get-text-example-way1.js


// A URL returns TEXT data.
var url = "https://ex1.o7planning.com/_testdatas_/simple-text-data.txt";

function doGetTEXT()  {
  // Call fetch(url) with default options.
  // It returns a Promise object (Resolve response object)
  var aPromise = fetch(url);
  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok)  {
            throw new Error("HTTP error, status = " + response.status);
        }
        response.text()
          .then(function(myText) {
               console.log("Text:");
               console.log(myText);
          })
          .catch(function(error) {
             // Never happened.
          });
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        // Network Error!
        console.log(error);
    });
}

Fetch API được thiết kế để bạn có thể thực hiện các nhiệm vụ theo một dây chuyền (Chain), điều này có thể là vì phương thức promise.then(..), promise.catch(..) cũng được thiết kế để trả về một lời hứa.

Cho dù hàm function(response) mà bạn viết trả về một giá trị thông thường hay trả về một đối tượng Promise, thì phương thức then() luôn trả về một Promise.


get-text-example-way2.js


// A URL returns TEXT data.
var url = "https://ex1.o7planning.com/_testdatas_/simple-text-data.txt";

function doGetTEXT()  {
  // Call fetch(url) with default options.
  // It returns a Promise object (Resolve response object)
  var aPromise = fetch(url);

  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok)  {
            throw new Error("HTTP error, status = " + response.status);
        }
        return response.text();
    })
    .then(function(myText)  {
         console.log("Text:");
         console.log(myText);
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        // Network Error!
        console.log(error);
    });
}

get-text-example.html







    fetch get text
    
    


    

fetch get text

Click the button and see the results in the Console .

3- Get JSON – response.json()

Sử dụng Fetch API để gửi một yêu cầu và nhận về một JSON sẽ phức tạp hơn một chút so với gửi yêu cầu để nhận về một văn bản. Bởi vì bạn cần xử lý lỗi xẩy ra khi JSON có định dạng không hợp lệ hoặc dữ liệu NULL.

json-simple-data.json


{
  "fullName" : "Tom Cat",
  "gender" : "Male",
  "address" : "Walt Disney"
}

 

Hàm fetch(..) trả về một lời hứa giải quyết một đối tượng response.

Bước 1 ( Step 1 ), hãy viết code của bạn đơn thuần như sau :
get-json-example.js ( Step 1 )


// A URL returns JSON data.
var url = "https://ex1.o7planning.com/_testdatas_/json-simple-data.json";

function doGetJSON()  {
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);

  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        console.log(error);
    });
}

Way 1 :

Phương thức response.json() trả về một lời hứa giải quyết (resolve) một đối tượng JSON, vì vậy bạn có thể sử dụng phương thức response.json().then(..).

get-json-example_way1. js


// A URL returns JSON data.
var url = "https://ex1.o7planning.com/_testdatas_/json-simple-data.json";

function doGetJSON()  {
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);

  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok) {
           throw new Error("HTTP error, status = " + response.status);
        }
        // Get JSON Promise from response object:
        var myJSON_promise = response.json();

        // Work with Promise object:
        myJSON_promise.then(function(myJSON))  {
          console.log("OK! JSON:");
          console.log(myJSON);
        }
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        console.log(error);
    });
}

Way 2 :
get-json-example-way2.js


// A URL returns JSON data.
var url = "https://ex1.o7planning.com/_testdatas_/json-simple-data.json";

function doGetJSON()  {
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);
  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok) {
           throw new Error("HTTP error, status = " + response.status);
        }
        // Get JSON Promise from response object:
        var myJSON_promise = response.json();

        // Returns a Promise object.
        return myJSON_promise;
    })
    .then(function(myJSON) {
        console.log("OK! JSON:");
        console.log(myJSON);
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        console.log(error);
    });
}

get-json-example.html







    fetch get json
    
    


    

fetch get json

Click the button and see the results in the Console.


Null JSON Data ?

Chú ý: Phương thức response.json() có thể ném ra một lỗi, nếu URL của bạn trả về một dữ liệu không phải JSON, hoặc JSON không hợp lệ, hoặc một dữ liệu rỗng.

Giả sử bạn gửi một yêu cầu (request) để lấy thông tin của một nhận viên theo ID. Trường hợp nhân viên tồn tại bạn sẽ nhận được một dữ liệu JSON, ngược lại nếu nhân viên không tồn tại bạn sẽ nhận được một dữ liệu NULL. Tuy nhiên một dữ liệu NULL gây ra lỗi tại vị trí gọi response.json(). Hãy xem ví dụ:

  • http://example.com/employee?id=123

// Get information of Employee 123:
fetch("http://example.com/employee?id=123")
  .then(function(response) {
      console.log("OK! Server returns a response object:");
      console.log(response);

      if(!response.ok) {
         throw new Error("HTTP error, status = " + response.status);
      }
      // Error if Employee 123 does not exist.
      // (*** URL returns null).
      var myJSON_promise = response.json(); // =====> Error
      return myJSON_promise;
  })
  .then(function(myJSON) {
      console.log("OK! JSON:");
      console.log(myJSON);
  })
  .catch(function(error)  {
      console.log("Noooooo! Something error:");
      console.log(error);
  });

( Error )



SyntaxError: Unexpected end of JSON input

Hãy sử dụng response.text() thay vì response.json():

get-json-null-example.js


// A URL returns null JSON data.
var url = "https://ex1.o7planning.com/_testdatas_/json-null-data.json";

function doGetJSON()  {
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);
  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok) {
           throw new Error("HTTP error, status = " + response.status);
        }
        // Get TEXT Promise object from response object:
        var myText_promise = response.text();
        return myText_promise;
    })
    .then(function(myText) {
        console.log("OK! TEXT:");
        console.log(myText);
        var myJSON = null; 
        if(myText != null && myText.trim().length > 0)  {
            myJSON = JSON.parse(myText);
        }
        console.log("OK! JSON:");
        console.log(myJSON);
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        console.log(error);
    });
}

get-json-null-example.html







    fetch get json
    

    



    

fetch get null json

Click the button and see the results in the Console .

4- Get Blob – response.blob()

Phương thức response.blob() trả về một lời hứa giải quyết (resolve) một đối tượng Blob.

Ví dụ dưới đây tôi sẽ sử dụng Fetch API để download một ảnh cho bởi một URL và hiển thị nó trên trang.

get-blob-example.js


// A URL returns Image data (Blob).
var url = "https://ex1.o7planning.com/_testdatas_/triceratops.png";

function doGetBlob()  {
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);

  // Work with Promise object:
  aPromise
    .then(function(response) {
        console.log("OK! Server returns a response object:");
        console.log(response);
        if(!response.ok) {
           throw new Error("HTTP error, status = " + response.status);
        }
        // Get Blob Promise from response object:
        var myBlob_promise = response.blob();
        return myBlob_promise;
    })
    .then(function(myBlob) {
        console.log("OK! Blob:");
        console.log(myBlob);
        var objectURL = URL.createObjectURL(myBlob);
        var myImage = document.getElementById("my-img");
        myImage.src = objectURL;
    })
    .catch(function(error)  {
        console.log("Noooooo! Something error:");
        console.log(error);
    });
}

get-blob-example.html







    fetch get blob
    
    


    

fetch get Blob

Click the button to load Image .

5- Get ArrayBuffer – response.arrayBuffer()

Phương thức response.arrayBuffer() trả về một lời hứa giải quyết (resolve) đối tượng ArrayBuffer.

Dữ liệu được tải về dưới dạng bộ đệm (buffer) giúp bạn có thể làm việc ngay với nó mà không cần phải chờ đợt toàn bộ dữ liệu được download về, chẳng hạn một Video có dung lượng lớn, bạn có thể xem Video trong khi dữ liệu của nó vẫn đang được tải về trình duyệt của bạn.

Dưới đây là một ví dụ sử dụng Fetch API để chơi một file nhạc.

get-arraybuffer-example.js


// A URL returns Audio data.
var url = "https://ex1.o7planning.com/_testdatas_/yodel.mp3";

// AudioContext
const audioContext = new AudioContext();
var bufferSource;
// Get ArrayBuffer (Audio data) and play it.
function doGetArrayBuffer()  {
  bufferSource = audioContext.createBufferSource(); 
  bufferSource.onended =  function () {
      document.getElementById("play").disabled=false;
  };
  // Call fetch(url) with default options.
  // It returns a Promise object:
  var aPromise = fetch(url);

  // Work with Promise object:
  var retPromise =
   aPromise
    .then(function(response) {
        if(!response.ok)  {
           throw new Error("HTTP error, status = " + response.status);
        }
        // Get ArrayBuffer Promise object from response object:
        var myArrayBuffer_promise = response.arrayBuffer();
        return myArrayBuffer_promise;
    })
    .then(function(myArrayBuffer) {

        audioContext.decodeAudioData(myArrayBuffer, function(decodedData) {
          bufferSource.buffer = decodedData;
          bufferSource.connect(audioContext.destination);
        });
    });
    return retPromise;
}
function playIt()  {
    console.clear();
    doGetArrayBuffer()
       .then(function() {
            document.getElementById("play").disabled=true;
            bufferSource.start(0);
       })
       .catch(function(error){
            alert("Something Error: " + error.message);
       });
}
function stopIt()  {
    bufferSource.stop(0);
    document.getElementById("play").disabled=false;
}

get-arraybuffer-example.html







    fetch get ArrayBuffer
    
    


    

fetch get ArrayBuffer

Click the button to play Audio .

Web Audio API giúp bạn có thể làm việc với Audio trên môi trường web, nó là một API lớn và có liên quan tới Fetch API, nếu quan tâm bạn có thể tham khảo bài viết dưới đây:

6- Get FormData – response.formData()

Phương thức response.formData() trả về một lời hứa giải quyết (resolve) đối tượng FormData. Bạn thường sử dụng phương thức này tại Service Workers. Khi người dùng gửi dữ liệu Form tới máy chủ, dữ liệu này sẽ đi qua Service Workers trước khi tới máy chủ. Tại Service Workers bạn có thể gọi phương thức response.formData(), và sửa đổi các giá trị trong FormData nếu muốn.

  • TODO Link ?