Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch 实现 Abort #68

Open
pfan123 opened this issue May 28, 2020 · 0 comments
Open

Fetch 实现 Abort #68

pfan123 opened this issue May 28, 2020 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented May 28, 2020

Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。

fetch(String url, [, Object options]).then(function(response) { ... }).catch(err => {})

目前,浏览器端原生获取数据,发请求的主要是 XMLHttpRequestfetchXMLHttpRequest 作为元老级的存在, fetch 是在 ES6 中推出的更现代的 API。XMLHttpRequest 本身是支持请求中断的 abort , 而 fetch 不支持 abort,不过目前可以通过 AbortController 实现。

fetch 设计之初是不支持中断的,开发者 2015 年在 GitHub 上提的 issue ,目前解决方案还在讨论阶段,其中就包括 cancelable-promises 及其他 hack 方法。

const c = new FetchController
fetch(url, {controller: c})
c.abort()
// 或
fetch(url, {controller: c => c.abort()})

但是,现在有了通用的 AbortControllerAbortSignal API,这些 API 是由 DOM 标准规范 提供的,而不是由语言本身提供的。

什么是 AbortController?

AbortController 接口代表一个控制器对象,允许在需要时中止一个或多个 DOM 请求。

使用 AbortController.AbortController() 构造函数创建一个新的 AbortController 对象。 使用 AbortSignal 对象完成与DOM请求的通信。

// 构造一个新的 AbortController 对象实例
AbortController.AbortController()  // 目前大部分浏览器不支持此方法构造

const controller = new AbortController()

// 返回一个AbortSignal对象实例,它可以用来 with/abort 一个DOM请求
AbortController.signal 

// 中止一个尚未完成的DOM请求, 能够中止fetch 请求,任何响应Body的消费者和流
AbortController.abort()

以下是 AbortController 的基本用法

// 创建 AbortController 的实例
const controller = new AbortController()
const signal = controller.signal

// 监听 abort 事件,在 controller.abort() 执行后执行回调打印 
signal.addEventListener('abort', () => {
    console.log(signal.aborted) // true
})

// 触发中断
controller.abort()

浏览器支持情况

查询支持情况 AbortController,整体支持性不是特别好, 可以使用 abort-controller/polyfilabort-controller控件

fetch_abortcontroller

使用 AbortController 中断 fetch 请求

fetch 接受 AbortSignal 作为第二个参数的一部分。

const controller = new AbortController()
const signal = controller.signal

fetch('http://jd.com', { signal })
    .then(r => r.json())
    .then(response => console.log(response))
    .catch(err => {
        if (err.name === 'AbortError') {
    	    console.log('Fetch was aborted')
        } else {
    	    console.log('Error', err)
        }
    })

// 在 2s 后中断请求,将触发 'AbortError'
setTimeout(() => controller.abort(), 2000)

触发 controller.abort() 会中断 fetch 的 request 和 response。AbortController 不仅适用于 fetch,可以适用到中止任意异步事件。

思考

客户端中断请求反馈失败提示,但服务端会出现真实处理,状态变成成功了,导致客户端刷新页面状态变更了,那这种不一致一般使用优化策略 幂等机制

Other Resources

@pfan123 pfan123 changed the title Fetch 实现 abort Fetch 实现 Abort May 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant