iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
0

DAY 24. JavaScript Fetch API

JavaScript Fetch API 與XMLHttpRequest一樣用於AJAX操作,但操作上更加直覺合理。

全局方法fetch將回傳Promise,且不管伺服器端回應狀態碼是否為200都將會被以resolve的方式處理,但回應body將會帶有屬性ok,其數值將會是falsetrue來表示請求是否成功。

fetch

/*
 | fetch 是個全局方法,而不是建構子
 */
console.log(Fetch) // Fetch is not defined
console.log(window.fetch) // ƒ fetch() { [native code] }

/*
 | fetch 接受 Request 物件作為參數
 | 但也可以傳給他符合建構Request 物件的參數作為參數。
 */

// 這樣使用
const req = new Request(URL, {method: 'GET', cache: 'reload'})
fetch(req)
    .then(res => console.log(res))

// 或是這樣
fatch(URL, {method: 'POST'})
    .then(res => console.log(res))

了解到以上這個重點後就知道我們要了解的其實是Request建構子

Request

Request建構子接受一個或兩個參數
第一個參數是URL,第二個參數則是可選的物件

範例

const req = new Request('https://www.apple.com/ac/structured-data/images/knowledge_graph_logo.png?201709101434')
fetch(req)
    .then(res => {
        /* 
        | res 是個 Response 物件
        | 必須將它轉為 blob, formData, json .. 等格式
        */
        return res.blob()
    })
    .then(blob => {
        /*
        | 在這裡我們要將blob轉為圖片src
        | 使用 URL.createObjectURL
        */
        const img = new Image
        
        // 允許跨域,確保可以正確用於 canvas
        img.crossOrigin = 'anonymous'
        
        // 將blob 轉為dataURL
        img.src = URL.createObjectURL(blob)
        
        // 將元素渲染至 body
        document.body.appendChild(img)
    })

在此範例中我們可以發現回傳值res是個Response物件實例
我們無法直接使用,因此要將它轉為正確的資料格式,查看Response MDNMethods了解完整資訊

Headers

Request物件中有一個屬性headers
headers屬性接受一個鍵值對的物件
物件的操作本身雖然相當容易
但我們還是能夠以更聰明更可讀的方法來操作它,Headers物件


/*
 | 實例化一個headers物件
 | 接著我們就可以有幾個實用的方法
 | Headers建構子接受一個選擇性物件的物件作為參數
 | 我們可以直接定義headers需要的key與value
 */
const init = { '_token': 'hello12345world' }
const headers = new Headers(init)
console.log(headers.get('_token'))  // hello12345world

/*
 | has方法測試headers是否有屬性 test
 */
const hasToken = headers.has('_token')
console.log(hasToken)   // true
const hasTest = headers.has('test')
console.log(hasTest)    // false

/*
 | get方法取得headers中指定屬性key的值
 | 若指定key不存在則回傳 null
 */
const token = headers.get('_token')
console.log(token)  // "hello12345world"

const token2 = headers.get('_token2')
console.log(token2)

/*
 | set方法重設屬性的值
 | 若指定key不存在則會新增至headers
 */
headers.set('_token2', 'it 30 days')
console.log(headers.get('_token2')) "it 30 days"

 /*
 | append方法為headers物件添加屬性
 */
headers.append('my-header', '1234567890')
console.log(headers.get('my-header')) // "1234567890"
 
 /*
 | keys 方法, 回傳所有headers物件的keys
 | 可以簡單使用 for/of 迴圈枚舉
 */
for(let key of headers.keys()) {
    console.log(key)
}
 // _token

 /*
  | values() 方法, 回傳headers物件的values
  | 可以簡單使用 for/of 迴圈枚舉
  */
for(let value of headers.values()) {
    console.log(value)
}
// hello12345world

for(let prop of headers.entries()) {
    const [key, value] = prop
    console.log(key, value)
}
// _token hello12345world

Response

fetch方法回傳Promise
且不管伺服器響應為何都將resolve一個Response實例
所以我們要使用Response物件所提供的方法
將回傳先轉成我們所需要的資料格式在做使用。

範例(一)


const req = new Request('https://www.apple.com/ac/structured-data/images/knowledge_graph_logo.png?201709101434')

fetch(req)
    .then(res => {
        console.log(res.constructor.name)   // "Response"
        return res.blob()
    })
    .then(imgBlob => {
        const imgSrc = URL.createObjectURL(imgBlob)
        const image = new Image
        image.src = imgSrc
        document.body.appendChild(image)
        // 更多的處理 ...
    })

這個範例展示了兩個重點
第一、fetch方法回傳的resolve是個Response實例
第二、Response實例需要經過處理(例如範例中的.blob())才能真正被使用

完整的Response方法請參閱Response MDN文件

範例(二)


const headers = new Headers({
    '_token': 'thisismytoken'
})

const formData = new FormData()
formData.append('email', 'example@mail.com')

const req = new Request('https://my/perfect/api.io', {
    method: 'POST',
    headers: headers,
    body: formData
})

fetch(req)
    .then(res => res.json())
    .then(resJson => {
        console.log(resJson)
        // 做些什麼 ...
    })

範例二表示了一個比較完整fetch使用範例
範例中Request的屬性body可以有多種類型,詳細請參閱Request MDN

本篇主要說明了全局方法fetch的使用方式,以及相關的幾個物件,希望有給大家一些想法。

資料來源


上一篇
DAY 23. Webpack 設定
下一篇
DAY 25. JavaScript Canvas 操作
系列文
重新學習網頁設計30

尚未有邦友留言

立即登入留言