Fetch API

由于并不想直接抄袭API (因为并没有什么乱用,所以例行帖链接)。也会持续关注文档的中文翻译。API链接

兼容性

Can I use: http://caniuse.com/#search=fetch

然而事实是:

  • Edge

Can I use上这样写道 *Version number used for Edge is based on the number of EdgeHTML rather than Edge itself. This is because EdgeHTML is the engine for Edge that is related to feature support change.

也就是说,Edge版本不一样也有没实现。现实告诉我们。Edge浏览器,==目前支持的版本,也是有问题的==。不能算长连接,会被其他js操作打断挂起。音频视频文件在Edge上不要用fetch。

  • Safari

最新的safari 10.1已经可以了 tech preview 也可以。可惜这两种没有人用。

使用

1
2
3
4
5
var request = new Request(url,initParams);
fetch(request, initParams).then(function(response) {
// Do Something
});

推荐这样用,因为之前看到这样一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let headers = new self.Headers();
if (typeof seekConfig.headers === 'object') {
let configHeaders = seekConfig.headers;
for (let key in configHeaders) {
if (configHeaders.hasOwnProperty(key)) {
headers.append(key, configHeaders[key]);
}
}
}
let params = {
method: 'GET',
headers: headers,
mode: 'cors',
cache: 'default'
};
self.fetch(seekConfig.url, params).then((res) => {
});

这段代码,运行起来是没有任何问题的。但是代码并不是十分规范。个人推测,作者可能不是很懂网络请求。

MDN对fetch的说明很清楚因为是基于 request 和 response的请求,会有比较高的拓展性。相应的,浏览器也对request 和 response 基础特征进行了封装。也就是 Request() 和 Response() 规范化的表述了这两类对象所具有的属性和方法。这段代码中 request 中的 header用法是正确的。却没有建立相应的request.这样造成对于网络请求的调理并不是很清晰,更重要的一点是,在发送请求的时候,没有用Request,其中会有一些方法,未被定义。暂时看来,在这种场景下没有出现问题。但很可能他人会在后续开发中犯错误。

说完请求,要说下返回。还是觉得再看本文前应先看文档。所以不再这里赘述。几个值得注意的东西。response.ok 说明链接成功,可以开始拉取数据。

当数据类型为普通短链时,与 xmlhttprequest 差别不大,文档完全能看懂。这里只说流媒体长链的情况。

首先先说所谓的长链是个什么东西。

短链链接流程:

1
2
3
4
5
6
sequenceDiagram
客户端->>服务器: 哈罗
服务器->>客户端: 哈罗
客户端->>服务器: 你把那妹子电话给我
服务器->>客户端: {name:小花,phone:XXXXX}
客户端->>服务器: 谢了,88

也就是说,每次跟服务器要点东西都得打个招呼。Fetch 这回引入的流媒体长链,个人认为意义深远。基本是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
sequenceDiagram
客户端->>服务器: 哈罗
服务器->>客户端: 哈罗
客户端->>服务器: 你把那个小电影给我
服务器->>客户端: 小电影片段一: 格式FLV
服务器->>客户端: 小电影片段二: 扩展信息
服务器->>客户端: 小电影片段三: 音频流头信息
服务器->>客户端: 小电影片段四: 视频流头信息
服务器->>客户端: 小电影片段五: 音频流数据
服务器->>客户端: 小电影片段四: 视频流数据
服务器->>客户端: ...
服务器->>客户端: 小电影片段四千, 大兄弟我发完了
客户端->>服务器: 谢了,88

在获取每一段信息的同时,客户端就可以进行处理了。具体就是这样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
var request = new Request(url,initParams);
function processor(reader) {
return reader.read().then(function(result) {
// result.done 有没有发完
// result.value 数据
return processor(reader);
});
}
fetch(request, initParams).then(function(response) {
processor(response.body.getReader());
});

讲解一下,这里用到的是一个ReadableStream 的概念。获取一段流媒体时,response.body 是个 ReadableStream 它有两个方法 getReader() 会返回一个 Promise。 另一个就是cancel 意思是客户端跟服务器说 “什么破玩意,我不要了”。

这段代码中, read()异步函数中,return 了一个process 的 Promise大致意思就是,当客户端读取完某段数据后,告诉它,咱继续读取下一段。当然,详细代码还需要判断链接是否成功,请求的数据是否发完了

同时,在response中也可以看到一个arrayBuffer, 注意,这个方法其实是个==promise 会resolve一个 ArrayBuffer== 但是长链情况下用,会在发完的时候彻底解析。