自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

前端JS發(fā)起的請求能暫停嗎?

開發(fā) 前端
有些人可能誤以為網(wǎng)絡請求和響應根本無法暫停。我在文章開頭特別提到了數(shù)據(jù)傳輸相關(guān)的內(nèi)容,并加了一句“理論上,應用層協(xié)議可以通過標記數(shù)據(jù)包序列號來實現(xiàn)暫停機制”。

在討論前端JS發(fā)起的請求是否能暫停時,需要明確兩個概念:什么狀態(tài)可以被認為是“暫?!??以及什么是JS發(fā)起的請求?

如何定義暫停?

暫停指的是臨時停止一個已經(jīng)開始但尚未完成的過程。這意味著這個過程可以在某個時間點被中斷,并在另一個時間點恢復。

什么是請求?

首先,讓我們介紹一下TCP/IP網(wǎng)絡模型。網(wǎng)絡模型從上到下分為應用層、傳輸層、網(wǎng)絡層和網(wǎng)絡接口層。

上圖表示,每次網(wǎng)絡傳輸,應用數(shù)據(jù)都需要通過網(wǎng)絡模型逐層打包,然后發(fā)送到目的地,就像寄包裹一樣。要寄送的物品首先被包裝并登記其大小,然后放入箱子并登記目的地,最后裝上運輸工具送到目的地。

請求的概念可以理解為客戶端通過多次數(shù)據(jù)網(wǎng)絡傳輸將完整數(shù)據(jù)發(fā)送到服務器,而服務器為特定請求返回的數(shù)據(jù)可以稱為響應。

理論上,應用層協(xié)議可以通過標記數(shù)據(jù)包序列號來實現(xiàn)暫停機制。然而,TCP協(xié)議不支持這一點。TCP協(xié)議的數(shù)據(jù)傳輸是面向流的,數(shù)據(jù)被視為連續(xù)的字節(jié)流??蛻舳税l(fā)送的數(shù)據(jù)將被分成多個獨立傳輸?shù)腡CP段。無法直接控制每個TCP段的傳輸,因此無法實現(xiàn)暫停請求或響應的功能。

回答問題

如果請求指的是網(wǎng)絡模型中的傳輸,那么自然是不可能暫停的。

考慮到使用場景——由JS發(fā)起的請求。因此,可以認為這里的問題指的是在JS運行時發(fā)起的XMLHttpRequest或fetch請求。由于請求已經(jīng)發(fā)出,問題自然變成響應是否可以暫停。

我們都知道,上傳大文件分片和下載大文件本質(zhì)上是定義分片順序,按順序請求,可以通過中斷和記錄中斷點來實現(xiàn)暫停和恢復。然而,單個請求并沒有這樣的環(huán)境。

使用JS實現(xiàn)“假暫?!睓C制

雖然我們無法真正實現(xiàn)暫停請求,但我們可以模擬一個假暫停功能。在前端業(yè)務場景中,數(shù)據(jù)在接收到后不會立即顯示在客戶端。前端開發(fā)人員需要先處理這些數(shù)據(jù),然后再渲染到界面上。如果我們在發(fā)起請求前添加一個控制器,并且在請求返回時該控制器處于暫停狀態(tài),則不處理數(shù)據(jù)。相反,等待控制器恢復后再處理數(shù)據(jù)。這樣我們是否就達到了目標呢?讓我們嘗試實現(xiàn)它。

如果我們使用 fetch 發(fā)起請求,可以設計一個控制器 Promise,并結(jié)合請求使用 Promise.all 封裝。當 fetch 完成時,檢查控制器是否處于暫停狀態(tài);如果沒有暫停,直接resolve 控制器并同時 resolve 和拋出 Promise.all。

function _request () {
  return new Promise<number>((res) => setTimeout(() => {
    res(123)
  }, 3000))
}

// 原本想用 "class extends Promise" 實現(xiàn)。
// 問題在于https://github.com/nodejs/node/issues/13678。
function createPauseControllerPromise () {
  const result = {
    isPause: false,
    resolveWhenResume: false,
    resolve (value?: any) {},
    pause () {
      this.isPause = true
    },
    resume () {
      if (!this.isPause) return
      this.isPause = false
      if (this.resolveWhenResume) {
          this.resolve()
      }
    },
    promise: Promise.resolve()
  }
  
  const promise = new Promise<void>((res) => {
    result.resolve = res
  })
  
  result.promise = promise

  return result
}

function requestWithPauseControl <T extends () => Promise<any>>(request: T) {
  const controller = createPauseControllerPromise()
  
  const controlRequest = request().then((data) => {
      if (!controller.isPause) controller.resolve()
      controller.resolveWhenResume = controller.isPause
      return data
  })
  
  const result = Promise.all([controlRequest, controller.promise])
      .then(data => data[0])
      
  result.finally(() => controller.resolve())
  
  (result as any).pause = controller.pause.bind(controller);
  (result as any).resume = controller.resume.bind(controller);
  
  return result as ReturnType<T> & { pause: () => void, resume: () => void }
}

使用方法

我們可以將調(diào)用 _request 替換為調(diào)用 requestWithPauseControl(_request) ,并通過返回的pause和 resume 方法控制暫停和恢復。

const result = requestWithPauseControl(_request).then((data) => {
    console.log(data)
})

if (Math.random() > 0.5) { result.pause() }

setTimeout(() => {
    result.resume()
}, 4000)

執(zhí)行原理

在流程設計上,步驟如下:設計一個控制器,發(fā)起請求,在接收到響應后,檢查控制器的狀態(tài)。如果控制器不處于“暫?!睜顟B(tài),則正常返回數(shù)據(jù);如果控制器處于“暫停”狀態(tài),則將控制器設置為一旦調(diào)用resume方法就返回數(shù)據(jù)的狀態(tài)。

在代碼中,使用 Promise.all 將控制器 Promise 綁定。如果控制器處于暫停狀態(tài),Promise.all 不會被釋放。然后對應地暴露 pause 方法和 resume 方法供外部使用。

最后

有些人可能誤以為網(wǎng)絡請求和響應根本無法暫停。我在文章開頭特別提到了數(shù)據(jù)傳輸相關(guān)的內(nèi)容,并加了一句“理論上,應用層協(xié)議可以通過標記數(shù)據(jù)包序列號來實現(xiàn)暫停機制”。這意味著,如果你修改HTTP或設計自己的應用層協(xié)議(例如socket、vmess等協(xié)議),只要雙方支持該協(xié)議,就可以實現(xiàn)請求或響應的暫停。這不會影響TCP連接,但實現(xiàn)暫停機制需要綜合考慮場景和TCP策略,以確保更好的可靠性。

例如,提供一種控制消息類型來控制傳輸暫停,需要標記所有數(shù)據(jù)包的序列號。當需要暫停時,發(fā)送帶有序列號的暫停消息到接收端。接收端收到暫停消息后,將已收到的數(shù)據(jù)包標記塊返回給發(fā)送端(類似分片上傳機制)。

責任編輯:姜華 來源: 大遷世界
相關(guān)推薦

2017-08-17 13:56:30

JavascriptNode.jsHttp

2020-05-20 09:26:59

Node.jsDenoJavaScript

2023-12-12 09:45:16

前端瀏覽器

2019-07-23 10:20:23

前端Node.js中間層

2024-08-26 11:23:41

kitexcall

2023-11-23 23:52:06

options請求瀏覽器

2023-04-10 15:14:03

2019-03-28 11:00:37

前端網(wǎng)絡請求開發(fā)

2017-10-26 13:40:26

微信小程序Fly

2018-11-19 16:10:30

瀏覽器urlhttp

2020-11-09 11:10:56

前端api緩存

2022-01-23 08:26:57

微信暫停語音朗讀文字

2019-11-01 10:00:14

前端業(yè)務代碼

2022-01-28 14:20:53

前端代碼中斷

2021-09-26 06:43:07

封裝網(wǎng)絡請求

2024-08-26 08:47:32

2020-11-26 08:38:57

前端 js 庫vue

2022-01-21 19:00:44

前端JS框架

2021-03-09 16:30:50

Java前端框架開發(fā)

2015-08-07 10:06:26

加班編程熱情
點贊
收藏

51CTO技術(shù)棧公眾號