少女祈禱中...
Loading...
图片加载过慢?试试 从源站加载资源 X

ccloli

从 Fetch 到 Streams —— 以流的角度处理网络请求

Title image of Streams API by Mozilla Contributors is licensed under CC-BY-SA 2.5.

Title image of Streams API by Mozilla Contributors is licensed under CC-BY-SA 2.5.

此文章的略微润色版可前往 知乎掘金SegmentFault专栏 查看

在服务端开发中,流是一个很常见的概念。有了流我们就不再需要等待整个数据获取完毕后才处理数据,而是可以一段一段地拿到数据,在获得数据的同时直接解析数据。这样既可以高效利用 CPU 等资源,还减少了存放整个数据的内存占用。不过在过去,客户端 JavaScript 上都没有流的概念,而随着 Streams API 在各大浏览器上的逐步实现,我们终于可以使用原生的 API 以流的角度来看待数据了,例如从 fetch 请求上可以得到一个网络流。

既然标题是「从 Fetch 到 Streams」,那么首先让我们来看看既熟悉又陌生的 Fetch API。相比较于 XMLHttpRequestfetch() 的写法简单又直观,只要在发起请求时直接将整个配置项传入就可以了。fetch() 方法接受一个 Request 实例,或者是大家更常使用的方法——传入需要请求的 URL 以及一个可选的初始化配置项对象,然后就可以从 Promise 中取得返回的数据:

如果你不喜欢 Promise 的链式调用的话,还可以用 async/await

看起来相当的直观,在请求时直接将所有的参数传入 fetch() 方法即可,甚至相较于 XHR 还提供了更多的控制参数,例如是否携带 Cookie、是否需要手动跳转等;取出数据也只需要调用 Response 对象上的方法就能拿到格式化的数据(例如 res.json())。而直接使用 XMLHttpRequest 看起来就没那么方便了,初始化时既有方法的调用又有参数的赋值,看着还挺混乱的:

而随着 AbortControllerAbortSignal 在各大浏览器上完整实现,Fetch API 也能像 XHR 那样中断一个请求了,只是稍微绕了一点。通过创建一个 AbortController 实例,我们就得到了一个可以控制中断的控制器。这个实例的 signal 参数提供了一个 AbortSignal 实例,还提供了一个 abort() 方法用于发送中断信号。我们将 signal 传递进 fetch() 的初始化参数中,就可以在 fetch 请求之外控制请求的中断了:

只可惜提出这个解决方案并实装的时间还是有点晚,Fetch API 早在 就在 Firefox 上实现,并且最早于 在 Chrome 上实装。而该功能最早也是 Edge 浏览器在 2017 年 4 月实现,Safari 直到 2018 年末才被发现 AbortController 不能中断请求的 bug,最后在 2019 年 3 月的 Safari 12.1 中才正式解决。算下来从 Fetch API 在浏览器上实装开始,到主流现代浏览器全部支持,跨越了整整四年。

Image of AbortController & AbortSignal Support Table by caniuse.com is licensed under CC-BY 4.0.

Image of AbortController & AbortSignal Support Table by caniuse.com is licensed under CC-BY 4.0.

晚归晚,但是看起来现在的 Fetch API 已经无所不能了,不过在「真香」之前,我们来考虑一个很常见的场景:浏览器需要异步请求一个比较大的文件,由于可能比较耗时,希望在下载文件时展示文件的下载进度。XHR 提供了很多的事件,其中就包括了传输进度的 onprogress 事件,所以使用 XHR 可以很方便地实现这个功能:

但是 Fetch API 呢?你打开了 MDN,仔细地看了 fetch() 方法的所有参数,都没有找到类似 progress 这样的参数,毕竟 Fetch API 并没有什么回调事件。难道 Fetch API 就不能实现这么简单的功能吗?这里就要提到和它相关的 Streams API 了——不是 Web Socket,也不是 Media Stream,更不是只能在 Node.js 上使用的 Stream,不过和它很像。

READ MORE →

萝莉节存活报告

嗯,今天也还活着,不过倒也没什么想说的。

要说和今天相关的事情的话,其实,除了 xn--eekf.xn--q9jyb4c 这个域名以外,在半年前还买了个 loli.uno。当然,买了并不代表用上了,所以暂时就重定向到 xn--eekf.xn--q9jyb4c 上了。结果大概上个月的时候 IP 被墙了,所以其实你们现在直接连接也访问不了了。

smokeping-cloudcone

smokeping-cloudcone-2

traceroute 断在了 Multacom 机房的路由,ssh 后 traceroute 到国内的 IP 断在了骨干网,ping 其他邻居的 IP 基本没有事。所以应该不是屏蔽网段,而是直接针对 IP 屏蔽了。不过也奇怪应该没有什么大流量之类的,发现出问题的时候还在公司走 ss 用 Telegram,并没有什么大流量,不是很懂。嗯……难不成之前是瞎玩写的 xn--eckxj725iv5g.xn--eekf.xn--q9jyb4c 被发现了,然后就被屏蔽了?反正不是很懂,目前暂时靠 CloudFlare 续命,十一回家的时候发现家里的联通网络相性非常好,还能流畅在 YouTube 看阅兵(?

traceroute

另外上个月折腾了下 Oracle Cloud,选择了日本线路,延迟感人,绕道到 ping ~200ms,speedtest 到东京的测试服务器上行 48Mbps 下行 4Mbps,iperf3 也就 10Mbps。由于羊毛被褥的太狠,想开第二台机器做内网 iperf3 测试,结果开通的时候提示已经售罄了,所以至今不知道这玩意的网络配置是什么样,感觉或许还不如美西节点,美国节点还有免费邮件额度。相比之下韩国节点可是在公司跑到了 500Mbps 的,不过韩国基本不能访问 porn 也没什么用,日本节点再慢,至少还能看个 DMM(虽然也不知道能买什么,也不玩页游,所以……好像也没用)。

oracle-dmm

或许之后会试着在那个东京节点上做一份 mirror,有时间再折腾吧。对速度感兴趣的同学可以访问这个对象存储的链接,看看速度有多渣:https://objectstorage.ap-tokyo-1.oraclecloud.com/p/VdT8VdFqkU-e4Tex4GnHK-VA6XwCnH_7zjpnM_Xtnr4/n/nrzblovvku9x/b/bucket-ccloli/o/76825905_p0.jpg 。总之,这个东京节点路由不行,虽然 traceroute 机器的上一个路由是从广州出口直接到 Tata 的,不过还是很慢,对东亚用户来说还不如美国线路(韩国用户和日本用户除外?),反正现在的 ping 值比到位于西海岸 LA 的 Multacom 机房的 200ms 还高,夜间高峰期线路干扰更可怕,丢包率 50%……除了能访问只有日本 IP 能打开的网站外,还不如美西节点。

oracle-ping

嗯,总之,大概就这样吧,明年的存活报告或者明天见。

嗯,先赶在 23:59 前先发布了,然后再来编辑(

萌节存活报告

嗯,我还活着。

感觉每年十月十日发文章就当是存活报告好了。

嗯,就这样,明年见。