讓fetch也可以timeout

firmwu 8年前發布 | 18K 次閱讀 JavaScript開發 JavaScript

原生的HTML5 API fetch并不支持 timeout 屬性,習慣了jQuery的ajax配置的同學,如果一時在fetch找不到配置 timeout 的地方,也許會很糾結。fetch 的配置 API 如下:

語法

fetch(input, init).then(function(response) { ... });

參數

  • input

定義要獲取的資源。這可能是: 一個 USVString 字符串,包含要獲取資源的 URL。 一個 Request 對象。

  • init 可選 一個配置項對象,包括所有對請求的設置。可選的參數有:

method: 請求使用的方法,如 GET、POST。

headers: 請求的頭信息,形式為 Headers 對象或 ByteString。 body: 請求的 body 信息:可能是一個 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 對象。注意 GET 或 HEAD 方法的請求不能包含 body 信息。

mode: 請求的模式,如 cors、 no-cors 或者 same-origin。

credentials: 請求的 credentials,如 omit、same-origin 或者 include。

cache: 請求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.

根本找不到 timeout 配置,本文和大家分享如何快速實現 fetch 的 timeout 功能。

我們先實現 abort 功能,但由于初始化fetch后,返回的是一個Promise對象,那么需要在 abort 后達到觸發 reject Promise的效果。

如果要沿用fetch返回的Promise來實現 abort 估計是達不到效果的,這里需要借助自己的一個Promise實例來達到目的。

var abort_fn = null;
var abort_promise = new Promise(function(resolve, reject) {
     abort_fn = function() {
         reject('abort promise');
     };
 });

這個簡單的代碼段,可以通過調用 abort_fn 函數就可以觸發abort_promise的 reject 。

fetch 返回的promise 我們暫且稱為 fetch_promise 吧,那么現在有兩個 promise: abort_promise 和 fetch_promise 。

每個promise都可以綁定resolve callback 和 reject callbck,那么后續then的回調綁定到哪個promise上呢,這是一個問題。

這里我們使用Promise非常好用的 Promise.race 方法, 他可以幫我們解決這個問題:

Promise.race 概述

Promise.race(iterable)方法返回一個promise,這個promise在iterable中的任意一個promise被解決或拒絕后,立刻以相同的解決值被解決或以相同的拒絕原因被拒絕。

合體:

function abortablePromise(fetch_promise) {
      var abort_fn = null;

      //這是一個可以被reject的promise
      var abort_promise = new Promise(function(resolve, reject) {
             abort_fn = function() {
                  eject('abort promise');
              };
      });

      //這里使用Promise.race,以最快 resolve 或 reject 的結果來傳入后續綁定的回調
       var abortable_promise = Promise.race([
             fetch_promise,
             abort_promise
       ]);

       abortable_promise.abort = abort_fn;

       return abortable_promise;
}

經過 abortablePromise 包裹后的promise都會返回一個新的promise,不同的是帶上了一個abort方法。 使用例子:

var p = abortablePromise(fetch('//a.com/b/c'));
p.then(function(res) {
    console.log(res)
}, function(err) {
    console.log(err);
});

//假設fetch要3秒,但是你想在2秒就放棄了:
setTimeout(function() {
    p.abort(); // -> will print "abort promise"
}, 2000);

目前為止,大體功能已經實現,再稍微調整,讓調用更方便:

function _fetch(fetch_promise, timeout) {
      var abort_fn = null;

      //這是一個可以被reject的promise
      var abort_promise = new Promise(function(resolve, reject) {
             abort_fn = function() {
                eject('abort promise');
             };
      });

      //這里使用Promise.race,以最快 resolve 或 reject 的結果來傳入后續綁定的回調
       var abortable_promise = Promise.race([
             fetch_promise,
             abort_promise
       ]);

       setTimeout(function() {
             abort_fn();
        }, timeout);

       return abortable_promise;
}

//usage:
_fetch(fetch('//a.com/b/c'), 2000)
    .then(function(res) {
        console.log(res)
    }, function(err) {
        console.log(err);
    });

全文完

 

來自:http://imweb.io/topic/57c6ea35808fd2fb204eef63

 

 本文由用戶 firmwu 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!