fetch timeout + 緩存了解下

起因

我在網(wǎng)上看到很多關(guān)于fetch timeout的封裝乒疏,但是我覺得是偽timeout崎岂,只是拋錯逸月,但是fetch的Promise鏈會一直執(zhí)行下去

Promise.race([
  fetch('/api')
    .then(res => res.json())
    .then(res => console.log(555)),
  new Promise(function(resolve, reject) {
    setTimeout(() => {
      reject(new Error('request timeout'));
      console.log(111);
    }, 100);
  })
]);

結(jié)果:


image.png

可以看到就算超時后矩屁,fetch請求仍按正常順序執(zhí)行,輸出了555舔琅,超時一般會重新請求等恐,這樣到最后就有可能輸出2次或者多次555,試想如果你在then函數(shù)里面執(zhí)行setState操作备蚓,這樣視圖就會更新2次或者多次课蔬,這樣顯然不是我們想要的結(jié)果,我們想要的是獲取結(jié)果后執(zhí)行一次

針對以上缺點(diǎn)進(jìn)行改進(jìn)

于是我封裝以下代碼星著,支持timeout(我這個其實(shí)也是偽timeout购笆,沒辦法,除非使用xhr虚循,但是超時后Promise鏈只會執(zhí)行報錯,因為結(jié)果和報錯使用同一個Promise)和重新請求样傍,由于返回值是一個Promise横缔,用法和fetch保持一致
支持Promise.all,.race方法

代碼地址

class TimeoutError extends Error {
  constructor(message) {
    super(message);
    this.name = 'TimeoutError';
  }
}

/**
 * 提供參數(shù)校驗和wrapper功能
 *
 * @param {*} url
 * @param {*} [options={ method: 'GET' }]
 * @returns {Promise} the request result
 */
function request(url, options = { method: 'GET' }) {
  let retryCount = 0;

  let parseJSON = response => {
    return response.json();
  };

  let checkStatus = response => {
    if (response.status >= 200 && response.status < 300) {
      return response;
    }

    let error = new Error(response.statusText);
    error.response = response;
    throw error;
  };

  class Request {
    constructor(url, { retry, timeout, ...options }) {
      this.url = url;
      this.retry = retry || 0;
      this.timeout = timeout || 10000;
      this.options = options;
    }

    then(fn) {
      let done = false;
      setTimeout(() => {
        // 無論是請求重試還是最終超時錯誤,此次請求得到的結(jié)果作廢
        if (retryCount < this.retry && !done) {
          done = true;
          retryCount++;
          this.then(fn);
        } else {
          let error = new TimeoutError(`timeout of ${this.timeout}ms execeeded`);
          this.catchError(error);
        }
      }, this.timeout);

      fetch(this.url, this.options)
        .then(checkStatus)
        .then(parseJSON)
        .then(res => {
          // 未進(jìn)入重試或者超時錯誤衫哥,返回結(jié)果
          if (!done) {
            fn(res);
            done = true;
          }
        })
        .catch(err => {
          this.catchError(err);
        });

      return this;
    }

    catch(fn) {
      this.catchError = fn;
    }
  }

  return new Promise((resolve, reject) =>
    new Request(url, options).then(res => resolve(res)).catch(err => reject(err))
  );
}

request('/api', {
  retry: 2,
  timeout: 1000
}).then(res => console.log(res))

使用封裝后的fetch進(jìn)行請求

設(shè)置Cache-Control:2s和timeout:1000ms后的請求情況
可以看到1.49s后請求才完全響應(yīng)茎刚,而我們設(shè)置了1s重新請求,所以第二次請求由于上次請求緩存未失效的原因撤逢,在1.49s的時候利用了上次請求作為結(jié)果進(jìn)行了響應(yīng)
設(shè)置緩存膛锭,第一次超時請求結(jié)果作廢(then函數(shù)不執(zhí)行)粮坞,第二次請求直接拿了第一次的緩存,這樣減少了請求響應(yīng)時間還減輕了服務(wù)器的壓力


image.png

image.png

image.png

image.png

不設(shè)置緩存初狰,如果網(wǎng)絡(luò)那段時間不太好莫杈,第三次請求才順利拿到結(jié)果,也有可能第二次拿到請求奢入,抑或是重試2次以后還是超時了


image.png

image.png

請求重試最好跟cache-control配合使用筝闹,這樣當(dāng)前面請求超時結(jié)果作廢后,第二次請求會等到第一次請求結(jié)果的返回腥光,前提是緩存沒有失效
緩存失效時間是從響應(yīng)開始時計算的关顷,一般配合超時重新請求的話,timeout設(shè)置為正常響應(yīng)的1.5倍武福,max-age應(yīng)該設(shè)置為timeout的1.5+倍(或者為timeout的2倍议双,方便利用上次響應(yīng)結(jié)果),具體數(shù)值需要根據(jù)具體情況合理設(shè)置

可能最后會有人有這樣的疑問捉片,你使用緩存聋伦,即上一次請求超時響應(yīng)的結(jié)果,那還不如Promise.race的方法簡單界睁,一樣的效果
使用緩存的優(yōu)勢就是如果第一次超時響應(yīng)的時間短于timeout加正常響應(yīng)甚至又一次超時的時間觉增,而且緩存沒有失效,那么既節(jié)省了時間又節(jié)省了服務(wù)器的壓力翻斟,假如失效了呢逾礁?重新請求唄!不管怎樣访惜,利用緩存絕對是比不利用的好

最后嘹履,如果你覺得這篇文章對你有用的話,麻煩給個小星星债热,如有錯誤的話砾嫉,也歡迎指正

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市窒篱,隨后出現(xiàn)的幾起案子焕刮,更是在濱河造成了極大的恐慌,老刑警劉巖墙杯,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件配并,死亡現(xiàn)場離奇詭異,居然都是意外死亡高镐,警方通過查閱死者的電腦和手機(jī)溉旋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫉髓,“玉大人观腊,你說我怎么就攤上這事邑闲。” “怎么了梧油?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵苫耸,是天一觀的道長。 經(jīng)常有香客問我婶溯,道長鲸阔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任迄委,我火速辦了婚禮褐筛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叙身。我一直安慰自己渔扎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布信轿。 她就那樣靜靜地躺著晃痴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪财忽。 梳的紋絲不亂的頭發(fā)上倘核,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音即彪,去河邊找鬼紧唱。 笑死,一個胖子當(dāng)著我的面吹牛隶校,可吹牛的內(nèi)容都是我干的漏益。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼深胳,長吁一口氣:“原來是場噩夢啊……” “哼绰疤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舞终,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤轻庆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后权埠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榨了,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年攘蔽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呐粘。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡满俗,死狀恐怖转捕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唆垃,我是刑警寧澤五芝,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站辕万,受9級特大地震影響枢步,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渐尿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一醉途、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隘擎,春花似錦、人聲如沸凉夯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至征绎,卻和暖如春蹲姐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炒瘸。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拐邪,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓隘截,卻偏偏與公主長得像扎阶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子婶芭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容