1. 程式人生 > >react-native fetch的具體使用方法

react-native fetch的具體使用方法

原文:https://www.jb51.net/article/127286.htm

在前端快速發展地過程中,為了契合更好的設計模式,產生了 fetch 框架,此文將簡要介紹下 fetch 的基本使用。

在 AJAX 時代,進行請求 API 等網路請求都是通過 XMLHttpRequest 或者封裝後的框架進行網路請求。

現在產生的 fetch 框架簡直就是為了提供更加強大、高效的網路請求而生,雖然在目前會有一點瀏覽器相容的問題,但是當我們進行 Hybrid App 開發的時候,如我之前介紹的Ionic 和React Native,都可以使用 fetch 進行完美的網路請求。

fetch 初體驗

在 Chrome 瀏覽器中已經全域性支援了 fetch 函式,開啟除錯工具,在 Console 中可以進行初體驗。先不考慮跨域請求的使用方法,我們先請求同域的資源,如在我的部落格頁面中,開啟 Console 進行如下請求。

?

1

fetch("http://blog.parryqiu.com").then(function(response){console.log(response)})

返回的資料:

這樣就很快速地完成了一次網路請求,我們發現返回的資料也比之前的 XMLHttpRequest 豐富、易用的多。

關於 fetch 標準概覽

雖然 fetch 還不是作為一個穩定的標準釋出,但是在其一直迭代更新的 標準描述 中,我們發現已經包含了很多的好東西。

fetch 支援了大部分常用的 HTTP 的請求以及和 HTTP 標準的相容,如 HTTP Method,HTTP Headers,Request,Response。

fetch 的使用

fetch的入口函式定義在node_modules/whatwg-fetch.js檔案中,如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

self.fetch = function (input, init) {

 return new Promise(function (resolve, reject) {

  var request = new Request(input, init)

  var xhr = new XMLHttpRequest()

  xhr.onload = function () {

   var options = {

    status: xhr.status,

    statusText: xhr.statusText,

    headers: parseHeaders(xhr.getAllResponseHeaders() || '')

   }

   options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')

   var body = 'response' in xhr ? xhr.response : xhr.responseText

   resolve(new Response(body, options))

  }

  xhr.onerror = function () {

   reject(new TypeError('Network request failed'))

  }

  xhr.ontimeout = function () {

   reject(new TypeError('Network request failed888888888888'))

  }

  xhr.open(request.method, request.url, true)

  if (request.credentials === 'include') {

   xhr.withCredentials = true

  }

  if ('responseType' in xhr && support.blob) {

   xhr.responseType = 'blob'

  }

  request.headers.forEach(function (value, name) {

   xhr.setRequestHeader(name, value)

  })

  xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)

 })

}

該函式在Network/fetch.js中被匯出,最終在initializeCore.js中被註冊為global的屬性變為全域性函式。fetch返回的是一個Promise。

跟隨方法走向,依次呼叫的是XMLHttpRequest.js的send -> RCTNetworking.ios.js的sendRequest -> 最終調到原生端RCTNetworking.mm的sendRequest方法。

相關問題點:

1、為何fetch函式無法設定timeout?

為了設定fetch的timeout,我會如下定義一個函式

?

1

2

3

4

5

6

7

8

9

10

11

_timeout_fetch(fetch_promise, timeout = 15000) {

 let timeout_promise = new Promise(function (resolve, reject) {

  setTimeout(() => {

   reject('timeout promise');

  }, timeout)

 });

 return Promise.race([

  fetch_promise,

  timeout_promise

 ]);

}

然後如下呼叫

?

1

2

3

4

5

6

7

8

9

10

this._timeout_fetch(

   fetch(url, requestParams)

    .then(response => response.json())

    .then(responseData => {

     resolve(responseData);

    })

    .catch(error => {

     reject(error);

    })

  )

先定義一個Promise,其在超時時間結束後reject。將這個Promise和fetch合併到Promise.race中,則一旦這兩個請求誰先執行,另外一個會被捨棄。這樣完成超時時間的設定。

但是檢視原始碼發現oc中是有超時時間設定這個選項的,且js和oc通訊時也傳了這個引數,問題是出在入口函式fetch處,只需要在上面fetch方法中新增上如下

?

1

xhr.timeout = init.timeout || 0;

就可以在請求引數中設定超時時間了,如

?

1

2

3

4

5

6

7

let requestParams = {

  method: method,

  header: {

   "Content-Type": "application/json;charset=UTF-8",

  },

  timeout: 1000

 };

2、fetch函式為何無法cancel?

fetch在原生端是NSURLSessionDataTask發的請求,這個是可取消的。在js端的XMLHttpRequest.js中也發現了abort方法,呼叫能夠取消當前網路請求。問題出在了fetch的介面函式。

首先,要想請求能夠取消,得拿到當前請求對應的requestId。請求的執行順序是js端發起 -> OC生成Request,得到requestId,利用NSURLSessionDataTask發起請求 -> 將requestId通過回撥的形式傳回給js端,js若想取消該請求,執行abort方法即可。

要想fetch函式能夠執行cancel,只需該方法將XMLHttpRequest物件返回即可。但是那樣,就不再是一個Promise了。
也可以將cancel方法繫結到返回的Promise物件上,修改方法如下

?

1

2

3

4

5

6

7

8

9

10

11

self.fetch = function (input, init) {

 var xhr = new XMLHttpRequest()

 let p = new Promise(function (resolve, reject) {

  var request = new Request(input, init)

  // xhr的各種設定,回撥等

 })

 p.cancel = () => {

  xhr.abort()

 }

 return p;

}

如此,呼叫的時候就比較惡習了,要如下

?

1

2

3

4

5

6

let promise = fetch(url);

promise.then(res => {

}).then(res => {

}).catch(err => {

})

promise.cancel() // 取消該網路請求

不能fecth().then().then()的模式呼叫,因為這樣會導致返回的那個Promise不再是上面綁定了cancel的那個Promise。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援指令碼之家。