title: JavaScript高级程序设计第四版学习–第二十四章
date: 2021-5-31 10:46:01
author: Xilong88
tags: JavaScript

本章内容:
使用XMLHttpRequest 对象
处理XMLHttpRequest 事件
源域Ajax限制
Fetch API
Streams API
可能出现的面试题:
1.xhr对象的基本使用方法
2.聊聊HTTP头部
3.xhr的事件有哪些?
4.跨域问题了解过吗?有哪些解决方案
5.Fetch API用过吗?
6.Header对象和Request、Response对象了解过吗?
7.WebSocket了解过吗?

Streams API略

知识点:

1.XMLHttpRequest 对象

let xhr = new XMLHttpRequest();
xhr.open("get", "example.php", false);

使用XHR对象首先要调用open() 方法,这个方法接收3个参数:请求类型(“get” 、“post” 等)、请求URL,以及表示请求是否异步的布尔值。

xhr.open("get", "example.php", false);

只能访问同源URL,也就是域名相同、端口相同、协议相同。如果请求的URL与发送请求的页面在任何方面有所不同,则会抛出安全错误。

要发送定义好的请求,必须调用send() 方法:

xhr.open("get", "example.txt", false);
xhr.send(null);

send() 方法接收一个参数,是作为请求体发送的数据。如果不需要发送请求体,则必须传null ,因为这个参数在某些浏览器中是必需的。

收到响应后,XHR对象的以下属性会被填充上数据。

responseText :作为响应体返回的文本。
responseXML :如果响应的内容类型是"text/xml"
或"application/xml" ,那就是包含响应数据的XML DOM文
档。
status :响应的HTTP状态。
statusText :响应的HTTP状态描述。

XHR对象有一
个readyState 属性,表示当前处在请求/响应过程的哪个阶段。这个属
性有如下可能的值。

0:未初始化(Uninitialized)。尚未调用open() 方法。
1:已打开(Open)。已调用open() 方法,尚未调用send() 方
法。
2:已发送(Sent)。已调用send() 方法,尚未收到响应。
3:接收中(Receiving)。已经收到部分响应。
4:完成(Complete)。已经收到所有响应,可以使用了。

每次readyState 从一个值变成另一个值,都会触发readystatechange 事件。可以借此机会检查readyState 的值。一般来说,我们唯一关心的readyState 值是4,表示数据已就绪。

在收到响应之前如果想取消异步请求,可以调用abort() 方法:

xhr.abort();

2.HTTP头部

默认情况下,XHR请求会发送以下头部字段。

Accept :浏览器可以处理的内容类型。
Accept-Charset :浏览器可以显示的字符集。
Accept-Encoding :浏览器可以处理的压缩编码类型。
Accept-Language :浏览器使用的语言。
Connection :浏览器与服务器的连接类型。
Cookie :页面中设置的Cookie。
Host :发送请求的页面所在的域。
Referer :发送请求的页面的URI。注意,这个字段在HTTP规范
中就拼错了,所以考虑到兼容性也必须将错就错。(正确的拼写应
该是Referrer。)
User-Agent :浏览器的用户代理字符串。

setRequestHeader() 方法。这个方法接收两个参数:头部字段的名称和值。

为保证请求头部被发送,必须在open() 之后、send() 之前调用setRequestHeader()

getResponseHeader() 方法从XHR对象获取响应头部,只要传入要获取头部的名称即可。

如果想取得所有响应头部,可以使用getAllResponseHeaders() 方法,这个方法会返回包含所有响应头部的字符串

let myHeader = xhr.getResponseHeader("MyHeader");
let allHeaders  xhr.getAllResponseHeaders();
Date: Sun, 14 Nov 2004 18:04:03 GMT
Server: Apache/1.3.29 (Unix)
Vary: Accept
X-Powered-By: PHP/4.3.8
Connection: close
Content-Type: text/html; charset=iso-8859-1

3.GET请求

xhr.open("get", "example.php?name1=value1&name2=value2", true);
function addURLParam(url, name, value) {url += (url.indexOf("?") == -1 ? "?" : "&");url += encodeURIComponent(name) + "=" + encodeURIComponent(value);return url;
}
let url = "example.php";
// 添加参数
url = addURLParam(url, "name", "Nicholas");
url = addURLParam(url, "book", "Professional JavaScript");
// 初始化请求
xhr.open("get", url, false);

4.POST请求

xhr.open("post", "example.php", true);

服务器逻辑需要读取原始POST数据才能取得浏览器发送的数据。不过,可以使用XHR模拟表单提交。为此,第一步需要把ContentType 头部设置为"application/x-www-formurlencoded" ,这是提交表单时使用的内容类型。第二步是创建对应格式的字符串。

5.XMLHttpRequest Level 2

新增了FormData 类型

let data = new FormData();
data.append("name", "Nicholas");

append() 方法接收两个参数:键和值,相当于表单字段名称和该字段的值。

通过直接给FormData 构造函数传入一个表单元素,也可以将表单中的数据作为键/值对填充进去:

let data = new FormData(document.forms[0]);

timeout 属性

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {if (xhr.readyState == 4) {try {if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {alert(xhr.responseText);} else {alert("Request was unsuccessful: " + xhr.status);}} catch (ex) {// 假设由ontimeout处理}}
};
xhr.open("get", "timeout.php", true);
xhr.timeout = 1000; // 设置1秒超时
xhr.ontimeout = function() {alert("Request did not return in a second.");
};
xhr.send(null);

overrideMimeType() 方法

调用overrideMimeType() 可以保证将响应当成某种格式(这里例子是XML)而不是纯文本来处理:

let xhr = new XMLHttpRequest();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null);

为了正确覆盖响应的MIME类型,必须在调用send() 之前调用overrideMimeType() 。

6.进度事件

6个进度相关的事件。

loadstart :在接收到响应的第一个字节时触发。
progress :在接收响应期间反复触发。
error :在请求出错时触发。
abort :在调用abort() 终止连接时触发。
load :在成功接收完响应时触发。
loadend :在通信完成时,且在error 、abort 或load 之后触
发。

load 事件

load 事件在响应接收完成后立即触发,这样就不用检查readyState 属性了。

progress 事件

在浏览器接收数据期间,这个事件会反复触发。每次触发时,onprogress 事件处理程序都会收到event 对象,其target 属性是XHR对象,且包含3个额外属性:lengthComputable 、position 和totalSize

lengthComputable 是一个布尔值,表示进度信息是否可用;position 是接收到的字节数;totalSize 是响应的ContentLength 头部定义的总字节数。

7.跨源资源共享

跨源资源共享(CORS,Cross-Origin Resource Sharing)定义了浏览器与服务器如何实现跨源通信。CORS背后的基本思路就是使用自定义的HTTP头部允许浏览器和服务器相互了解,以确实请求或响应应该成功还是失败。

对于简单的请求,比如GET或POST请求,没有自定义头部,而且请求体是text/plain 类型,这样的请求在发送时会有一个额外的头部叫Origin 。Origin 头部包含发送请求的页面的源(协议、域名和端口),以便服务器确定是否为其提供响应。

如果服务器决定响应请求,那么应该发送Access-Control-Allow-Origin 头部,包含相同的源;或者如果资源是公开的,那么就包含"*"。比如:

Access-Control-Allow-Origin: http://www.nczonline.net

跨域XHR对象允许访问status 和statusText 属性,也允许同步请求。出于安全考虑,跨域XHR对象也施加了一些额外限制。

不能使用 setRequestHeader() 设置自定义头部。
不能发送和接收cookie。
getAllResponseHeaders() 方法始终返回空字符串。

预检请求

CORS通过一种叫预检请求 (preflighted request)的服务器验证机制,允许使用自定义头部、除GET和POST之外的方法,以及不同请求体内容类型。在要发送涉及上述某种高级选项的请求时,会先向服务器发送一个“预检”请求。这个请求使用OPTIONS方法发送并包含以下头部。

Origin :与简单请求相同。
Access-Control-Request-Method :请求希望使用的方法。
Access-Control-Request-Headers :(可选)要使用的逗号分
隔的自定义头部列表。

服务器会通过在响应中发送如下头部与浏览器沟通这些信息。

Access-Control-Allow-Origin :与简单请求相同。
Access-Control-Allow-Methods :允许的方法(逗号分隔的列
表)。
Access-Control-Allow-Headers :服务器允许的头部(逗号分
隔的列表)。
Access-Control-Max-Age :缓存预检请求的秒数。

凭据请求

默认情况下,跨源请求不提供凭据(cookie、HTTP认证和客户端SSL证书)。可以通过将withCredentials 属性设置为true 来表明请求会发送凭据。如果服务器允许带凭据的请求,那么可以在响应中包含如下HTTP头部:

Access-Control-Allow-Credentials: true

7.替代性跨源技术

图片探测
图片探测是与服务器之间简单、跨域、单向的通信。
任何页面都可以跨域加载图片而不必担心限制,因此这也是在线广告跟踪的主要方式。

let img = new Image();
img.onload = img.onerror = function() {alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";

JSONP

JSONP看起来跟JSON一样,只是会被包在一个函数调用里,比如:

callback({ "name": "Nicholas" });

JSONP格式包含两个部分:回调和数据。

下面是一个典型的JSONP请求:

http://freegeoip.net/json/?callback=handleResponse

首先,JSONP是从不同的域拉取可执行代码。如果这个域并不可信,则可能在响应中加入恶意内容。此时除了完全删除JSONP没有其他办法。在使用不受控的Web服务时,一定要保证是可以信任的。

第二个缺点是不好确定JSONP请求是否失败。虽然HTML5规定了<script> 元素的onerror 事件处理程序,但还没有被任何浏览器实现。为此,开发者经常使用计时器来决定是否放弃等待响应。这种方式并不准确,毕竟不同用户的网络连接速度和带宽是不一样的。

8.Fetch API

Fetch API则必须是异步

fetch() 只有一个必需的参数input 。多数情况下,这个参数是要获取资源的URL。这个方法返回一个期约:

let r = fetch('/bar');
console.log(r); // Promise <pending>
fetch('bar.txt').then((response) => {console.log(response);});
// Response { type: "basic", url: ...** **}

读取响应内容的最简单方式是取得纯文本格式的内容,这要用到text() 方法。这个方法返回一个期约,会解决为取得资源的完整内容:

fetch('bar.txt').then((response) => {response.text().then((data) => {console.log(data);});});
// bar.txt的内容

内容的结构通常是打平的:

fetch('bar.txt').then((response) => response.text()).then((data) => console.log(data));
// bar.txt的内容

处理状态码和请求失败

fetch('/bar').then((response) => {console.log(response.status);     // 200console.log(response.statusText); // OK});
fetch('/does-not-exist').then((response) => {console.log(response.status);     // 404console.log(response.statusText); // Not Found});

默认行为是跟随重定向并返回状态码不是300~399的响应。跟随重定向时,响应对象的redirected 属性会被设置为true,而状态码仍然是200:

fetch('/permanent-redirect').then((response) => {// 默认行为是跟随重定向直到最终URL// 这个例子会出现至少两轮网络请求// <origin url>/permanent-redirect -> <redirect url>console.log(response.status);     // 200console.log(response.statusText); // OKconsole.log(response.redirected); // true});

自定义选项

只使用URL时,fetch() 会发送GET请求,只包含最低限度的请求头。要进一步配置如何发送请求,需要传入可选的第二个参数init对象。init 对象要按照下表中的键/值进行填充。




headers



常见Fetch请求模式

发送JSON数据可以像下面这样发送简单JSON字符串:

let payload = JSON.stringify({foo: 'bar'
});
let jsonHeaders = new Headers({'Content-Type': 'application/json'
});
fetch('/send-me-json', {method: 'POST',   // 发送请求体时必须使用一种HTTP方法body: payload,headers: jsonHeaders
});

在请求体中发送参数因为请求体支持任意字符串值,所以可以通过它发送请求参数:

let payload = 'foo=bar&baz=qux';
let paramHeaders = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
});
fetch('/send-me-params', {method: 'POST',  // 发送请求体时必须使用一种HTTP方法body: payload,headers: paramHeaders
});

在请求体中发送参数
因为请求体支持任意字符串值,所以可以通过它发送请求参数:

let payload = 'foo=bar&baz=qux';
let paramHeaders = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
});
fetch('/send-me-params', {method: 'POST',  // 发送请求体时必须使用一种HTTP方法body: payload,headers: paramHeaders
});

发送文件

因为请求体支持FormData 实现,所以fetch() 也可以序列化并发送文件字段中的文件:

let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file']");
imageFormData.append('image', imageInput.files[0]);
fetch('/img-upload', {method: 'POST',body: imageFormData
});

这个fetch() 实现可以支持多个文件:

let imageFormData = new FormData();
let imageInput = document.querySelector("input[type='file'][multiple]");
for (let i = 0; i < imageInput.files.length; ++i) {imageFormData.append('image', imageInput.files[i]);
}
fetch('/img-upload', {method: 'POST',body: imageFormData
});

加载Blob文件 略

发送跨源请求

从不同的源请求资源,响应要包含CORS头部才能保证浏览器收到响应。没有这些头部,跨源请求会失败并抛出错误。

fetch('//cross-origin.com');
// TypeError: Failed to fetch
// No 'Access-Control-Allow-Origin' header is present on the requested resource.

如果代码不需要访问响应,也可以发送no-cors 请求。此时响应的type 属性值为opaque ,因此无法读取响应内容。这种方式适合发送探测请求或者将响应缓存起来供以后使用。

fetch('//cross-origin.com', { method: 'no-cors' }).then((response) => console.log(response.type));
// opaque

中断请求

let abortController = new AbortController();
fetch('wikipedia.zip', { signal: abortController.signal }).catch(() => console.log('aborted!');
// 10毫秒后中断请求
setTimeout(() => abortController.abort(), 10);
// 已经中断

9.Headers 对象

Headers 与Map 的相似之处

let h = new Headers();
let m = new Map();
// 设置键
h.set('foo', 'bar');
m.set('foo', 'bar');
// 检查键
console.log(h.has('foo')); // true
console.log(m.has('foo')); // true
console.log(h.has('qux')); // false
console.log(m.has('qux')); // false
// 获取值
console.log(h.get('foo')); // bar
console.log(m.get('foo')); // bar
// 更新值
h.set('foo', 'baz');
m.set('foo', 'baz');
// 取得更新的值
console.log(h.get('foo')); // baz
console.log(m.get('foo')); // baz
// 删除值
h.delete('foo');
m.delete('foo');
// 确定值已经删除
console.log(h.get('foo')); // undefined
console.log(m.get('foo')); // undefined

Headers 和Map 都可以使用一个可迭代对象来初始化,比如:

let seed = [['foo', 'bar']];
let h = new Headers(seed);
let m = new Map(seed);
console.log(h.get('foo')); // bar
console.log(m.get('foo')); // bar

而且,它们也都有相同的keys() 、values()和entries() 迭代器接口:

let seed = [['foo', 'bar'], ['baz', 'qux']];
let h = new Headers(seed);
let m = new Map(seed);
console.log(...h.keys());    // foo, baz
console.log(...m.keys());    // foo, baz
console.log(...h.values());  // bar, qux
console.log(...m.values());  // bar, qux
console.log(...h.entries()); // ['foo', 'bar'], ['baz', 'qux']
console.log(...m.entries()); // ['foo', 'bar'], ['baz', 'qux']

Headers 独有的特性

Headers 并不是与Map 处处都一样。在初始化Headers 对象时,也可以使用键/值对形式的对象,而Map 则不可以:

let seed = {foo: 'bar'};
let h = new Headers(seed);
console.log(h.get('foo')); // bar
let m = new Map(seed);
// TypeError: object is not iterable

一个HTTP头部字段可以有多个值,而Headers 对象通过append()方法支持添加多个值。在Headers 实例中还不存在的头部上调用append() 方法相当于调用set() 。后续调用会以逗号为分隔符拼接多个值:

let h = new Headers();
h.append('foo', 'bar');
console.log(h.get('foo')); // "bar"
h.append('foo', 'baz');
console.log(h.get('foo')); // "bar, baz"

头部护卫,对headers限制

10.Request 对象

通过构造函数初始化Request 对象。为此需要传入一个input参数,一般是URL:

let r = new Request('https://foo.com');
console.log(r);
// Request {...}

Request 构造函数也接收第二个参数——一个init 对象。这个init 对象与前面介绍的fetch() 的init 对象一样。没有在init对象中涉及的值则会使用默认值:

// 用所有默认值创建Request对象console.log(new Request(''));
// Request {//   bodyUsed: false
//   cache: "default"
//   credentials: "same-origin"
//   destination: ""
//   headers: Headers {}
//   integrity: ""
//   keepalive: false
//   method: "GET"
//   mode: "cors"
//   redirect: "follow"
//   referrer: "about:client"
//   referrerPolicy: ""
//   signal: AbortSignal {aborted: false, onabort: null}
//   url: "<current URL>"
// }
// 用指定的初始值创建Request对象
console.log(new Request('https://foo.com',{ method: 'POST' }));
// Request {//   bodyUsed: false
//   cache: "default"
//   credentials: "same-origin"
//   destination: ""
//   headers: Headers {}
//   integrity: ""
//   keepalive: false
//   method: "POST"
//   mode: "cors"
//   redirect: "follow"
//   referrer: "about:client"
//   referrerPolicy: ""
//   signal: AbortSignal {aborted: false, onabort: null}
//   url: "https://foo.com/"
// }

克隆Request 对象

let r1 = new Request('https://foo.com');
let r2 = new Request(r1);
console.log(r2.url); // https://foo.com/
let r1 = new Request('https://foo.com');
let r2 = new Request(r1, {method: 'POST'});
console.log(r1.method); // GET
console.log(r2.method); // POST

这种克隆方式并不总能得到一模一样的副本。最明显的是,第一个请求的请求体会被标记为“已使用”:

let r1 = new Request('https://foo.com',{ method: 'POST', body: 'foobar' });
let r2 = new Request(r1);
console.log(r1.bodyUsed); // true
console.log(r2.bodyUsed); // false

在fetch() 中使用Request 对象

let r = new Request('https://foo.com');
// 向foo.com发送GET请求
fetch(r);
// 向foo.com发送POST请求
fetch(r, { method: 'POST' });

fetch() 会在内部克隆传入的Request 对象。与克隆Request 一样,fetch() 也不能拿请求体已经用过的Request 对象来发送请求:

let r = new Request('https://foo.com',{ method: 'POST', body: 'foobar' });
r.text();
fetch(r);
// TypeError: Cannot construct a Request with a Request object that has already
been used.

关键在于,通过fetch 使用Request 会将请求体标记为已使用。也就是说,有请求体的Request 只能在一次fetch 中使用。

要想基于包含请求体的相同Request 对象多次调用fetch() ,必须在第一次发送fetch() 请求前调用clone() :

let r = new Request('https://foo.com',{ method: 'POST', body: 'foobar' });
// 3个都会成功
fetch(r.clone());
fetch(r.clone());
fetch(r);

11.Response 对象

可以通过构造函数初始化Response 对象且不需要参数。此时响应实例的属性均为默认值,因为它并不代表实际的HTTP响应:

let r = new Response();
console.log(r);
// Response {//   body: (...)
//   bodyUsed: false
//   headers: Headers {}
//   ok: true
//   redirected: false
//   status: 200
//   statusText: "OK"
//   type: "default"
//   url: ""
// }

Response 构造函数接收一个可选的body 参数。这个body 可以是null ,等同于fetch() 参数init 中的body 。还可以接收一个可选的init 对象,这个对象可以包含下表所列的键和值。

let r = new Response('foobar', {status: 418,statusText: 'I\'m a teapot'
});
console.log(r);
// Response {//   body: (...)
//   bodyUsed: false
//   headers: Headers {}
//   ok: false
//   redirected: false
//   status: 418
//   statusText: "I'm a teapot"
//   type: "default"
//   url: ""
// }

大多数情况下,产生Response 对象的主要方式是调用fetch() ,它返回一个最后会解决为Response 对象的期约,这个Response对象代表实际的HTTP响应。下面的代码展示了这样得到的Response 对象:

fetch('https://foo.com').then((response) => {console.log(response);});
// Response {//   body: (...)
//   bodyUsed: false
//   headers: Headers {}
//   ok: true
//   redirected: false
//   status: 200
//   statusText: "OK"
//   type: "basic"
//   url: "https://foo.com/"
// }

Response.redirect() 和Response.error() 。前者接收一个URL和一个重定向状态码(301、302、303、307或308),返回重定向的Response 对象:

console.log(Response.redirect('https://foo.com', 301));
// Response {//   body: (...)
//   bodyUsed: false
//   headers: Headers {}
//   ok: false
//   redirected: false
//   status: 301
//   statusText: ""
//   type: "default"
//   url: ""
// }

提供的状态码必须对应重定向,否则会抛出错误:

Response.redirect('https://foo.com', 200);
// RangeError: Failed to execute 'redirect' on 'Response': Invalid status code

另一个静态方法Response.error() 用于产生表示网络错误的Response 对象(网络错误会导致fetch() 期约被拒绝)。

console.log(Response.error());
// Response {//   body: (...)
//   bodyUsed: false
//   headers: Headers {}
//   ok: false
//   redirected: false
//   status: 0
//   statusText: ""
//   type: "error"
//   url: ""
// }

Response 对象包含一组只读属性,描述了请求完成后的状态,如下表所示。

克隆Response 对象

let r1 = new Response('foobar');
let r2 = r1.clone();
console.log(r1.bodyUsed); // false
console.log(r2.bodyUsed); // false

如果响应对象的bodyUsed 属性为true (即响应体已被读取),则不能再创建这个对象的副本。

12.Request 、Response 及Body 混入

Request 和Response 都使用了Fetch API的Body 混入,以实现两者承担有效载荷的能力

Body 混入提供了5个方法

Body.text() 方法返回期约,解决为将缓冲区转存得到的UTF-8格式字符串。

fetch('https://foo.com').then((response) => response.text()).then(console.log);
// <!doctype html><html lang="en">
//  <head>
//   <meta charset="utf-8">
//   ...
let request = new Request('https://foo.com',{ method: 'POST', body: 'barbazqux' });
request.text().then(console.log);
// barbazqux

Body.json()

Body.json() 方法返回期约,解决为将缓冲区转存得到的JSON。

fetch('https://foo.com/foo.json').then((response) => response.json()).then(console.log);
// {"foo": "bar"}
let request = new Request('https://foo.com',{ method:'POST', body: JSON.stringify({ bar: 'baz' }) });
request.json().then(console.log);// {bar: 'baz'}

Body.formData()

将FormData 对象序列化/反序列化为主体

let myFormData = new FormData();
myFormData.append('foo', 'bar');
fetch('https://foo.com/form-data').then((response) => response.formData()).then((formData) => console.log(formData.get('foo'));
// bar
let myFormData = new FormData();
myFormData.append('foo', 'bar');
let request = new Request('https://foo.com',{ method:'POST', body: myFormData });request.formData().then((formData) => console.log(formData.get('foo'));
// bar

Body.arrayBuffer()
将主体内容转换为ArrayBuffer 实例

fetch('https://foo.com').then((response) => response.arrayBuffer()).then(console.log);
// ArrayBuffer(...) {}
let request = new Request('https://foo.com',{ method:'POST', body: 'abcdefg' });
// 以整数形式打印二进制编码的字符串
request.arrayBuffer().then((buf) => console.log(new Int8Array(buf)));
// Int8Array(7) [97, 98, 99, 100, 101, 102, 103]

Body.blob()

以原始二进制格式使用主体

fetch('https://foo.com').then((response) => response.blob()).then(console.log);
// Blob(...) {size:..., type: "..."}
let request = new Request('https://foo.com',{ method:'POST', body: 'abcdefg' });
request.blob().then(console.log);
// Blob(7) {size: 7, type: "text/plain;charset=utf-8"}

一次性流 略
Beacon API 略

13.Web Socket

let socket = new WebSocket("ws://www.example.com/server.php");

WebSocket 也有一个readyState 属性表示当前状态。不过,这个值与XHR中相应的值不一样。

WebSocket.OPENING (0):连接正在建立。
WebSocket.OPEN (1):连接已经建立。
WebSocket.CLOSING (2):连接正在关闭。
WebSocket.CLOSE (3):连接已经关闭。

关闭Web Socket连接:

socket.close();

发送和接收数据

let socket = new WebSocket("ws://www.example.com/server.php");
let stringData = "Hello world!";
let arrayBufferData = Uint8Array.from(['f', 'o', 'o']);
let blobData = new Blob(['f', 'o', 'o']);
socket.send(stringData);
socket.send(arrayBufferData.buffer);
socket.send(blobData);

WebSocket 对象在连接生命周期中有可能触发3个其他事件。

open :在连接成功建立时触发。
error :在发生错误时触发。连接无法存续。
close :在连接关闭时触发。

JavaScript高级程序设计第四版学习--第二十四章相关推荐

  1. JavaScript高级程序设计红宝书学习笔记第三章基本概念

    第三章 基本概念 本章内容 语法 数据类型 操作符 语句 函数 3.1 语法 3.1.1 区分大小写,ECMAScript中的一切(变量.函数名和操作符)都区分大小写. 3.1.2 标识符 标识符:变 ...

  2. 《JavaScript高级程序设计》红宝书第二遍阅读(动手实践)

    <JavaScript高级程序设计>红宝书第二遍阅读(动手实践) 第1章--什么是JavaScript 第2章--HTML中的JavaScript 第3章--语言基础 第4章--变量.作用 ...

  3. Js高级程序设计第三版学习(十二章)

                                  Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3   1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...

  4. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  5. JavaScript高级程序设计 第4版----String

    JavaScript高级程序设计 第4版----String 文章目录 JavaScript高级程序设计 第4版----String 1.JavaScript 字符 2.字符串操作方法 1.conca ...

  6. JavaScript高级程序设计[第3版]

    JavaScript高级程序设计[第3版] package xyz.huning.toolkit.pdf;import java.io.FileOutputStream; import java.io ...

  7. 游戏策划学习第二十四天

    游戏策划学习第二十四天 5/23 5.社交:社交影响与关联性 6.稀缺:稀缺性与渴望 7.未知:未知性与好奇心 8.亏损:亏损与逃避心 最近在玩百闻牌,那就用百闻牌来思考这四项内容. 5.社交并不只是 ...

  8. javascript高级程序设计 第三版

    网盘地址 提取码:vh81 笔记 第二章 2.1script标签 <script>元素属性:async.charset.defer.language.src.type async和defe ...

  9. (学习总结)鸟哥基础篇第三版:第二十四章

    第二十四章. XWindow 設定介紹 24.1 什麼是 X Window System 24.1.1 X Window 的發展簡史 由於這個 X 希望能夠透過網路進行圖形介面的存取,因此發展出許多的 ...

最新文章

  1. 心酸科研路:3年前CVPR论文,仅被引用11次,如今成就黑洞照片!
  2. 基于MATLAB的小波去噪
  3. PowerDesigner的逆向工程.
  4. 云原生下,如何实现高可用的MySQL?
  5. SpringBoot2.0基础案例(01):环境搭建和RestFul风格接口
  6. 邮箱回执怎么看_考研复试联系导师邮件怎么写?
  7. 【NOIP2018】【Luogu5019】铺设道路(贪心,差分)
  8. vue、react等单页面项目应该这样子部署到服务器
  9. 如何在 iPhone 和 iPad 上快速找到合适照片?
  10. JAVA锁和volatile的内存语义volatile的使用场景
  11. ASP.NET Core 源码阅读笔记(3) ---Microsoft.AspNetCore.Hosting
  12. 计算机网络实验指导书 pdf,计算机网络实验指导书(新版).pdf
  13. 如何在WPS2000中插入AutoCad图形文件(转)
  14. 围棋AI kataGo下载
  15. 计算机控制技术第二版答案于微波,微波技术习题答案 2.doc
  16. AR智能眼镜tooz DevKit 20初体验
  17. PgSQL——学习笔记七: LIKE 子句:获取包含某些字符的数据 LIMIT 子句:限制 SELECT 语句中查询的数据的数量
  18. jmeter如何定位网络延时_JMeter 如何模拟不同的网络速度
  19. 瓦伦达效应:在大是大非面前不要在乎结果所带来的后果,你就会成功!
  20. [BZOJ2754]-[SCOI2012]喵星球上的点名-AC自动机+树状数组

热门文章

  1. Kali 2.0安装w3af
  2. ST-Link SWD接口接线
  3. C++ 调用 .lib 文件中的函数
  4. 汽车运行工况matlab代码,多个标准车辆行驶工况数据
  5. loss与metric的区别 以及 optimizer的介绍
  6. Ubuntu下如何录制gif动态图
  7. 大数据Spark学习笔记—未更完
  8. 京瓷1125打印机清零_京瓷打印一体机常见问题解答
  9. python批量创建文件夹
  10. uniapp 使用在线 iconfont 图标