JavaScript高级程序设计第四版学习--第二十四章
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高级程序设计第四版学习--第二十四章相关推荐
- JavaScript高级程序设计红宝书学习笔记第三章基本概念
第三章 基本概念 本章内容 语法 数据类型 操作符 语句 函数 3.1 语法 3.1.1 区分大小写,ECMAScript中的一切(变量.函数名和操作符)都区分大小写. 3.1.2 标识符 标识符:变 ...
- 《JavaScript高级程序设计》红宝书第二遍阅读(动手实践)
<JavaScript高级程序设计>红宝书第二遍阅读(动手实践) 第1章--什么是JavaScript 第2章--HTML中的JavaScript 第3章--语言基础 第4章--变量.作用 ...
- Js高级程序设计第三版学习(十二章)
Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3 1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...
- JavaScript高级程序设计第三版.CHM【带实例】
从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...
- JavaScript高级程序设计 第4版----String
JavaScript高级程序设计 第4版----String 文章目录 JavaScript高级程序设计 第4版----String 1.JavaScript 字符 2.字符串操作方法 1.conca ...
- JavaScript高级程序设计[第3版]
JavaScript高级程序设计[第3版] package xyz.huning.toolkit.pdf;import java.io.FileOutputStream; import java.io ...
- 游戏策划学习第二十四天
游戏策划学习第二十四天 5/23 5.社交:社交影响与关联性 6.稀缺:稀缺性与渴望 7.未知:未知性与好奇心 8.亏损:亏损与逃避心 最近在玩百闻牌,那就用百闻牌来思考这四项内容. 5.社交并不只是 ...
- javascript高级程序设计 第三版
网盘地址 提取码:vh81 笔记 第二章 2.1script标签 <script>元素属性:async.charset.defer.language.src.type async和defe ...
- (学习总结)鸟哥基础篇第三版:第二十四章
第二十四章. XWindow 設定介紹 24.1 什麼是 X Window System 24.1.1 X Window 的發展簡史 由於這個 X 希望能夠透過網路進行圖形介面的存取,因此發展出許多的 ...
最新文章
- 心酸科研路:3年前CVPR论文,仅被引用11次,如今成就黑洞照片!
- 基于MATLAB的小波去噪
- PowerDesigner的逆向工程.
- 云原生下,如何实现高可用的MySQL?
- SpringBoot2.0基础案例(01):环境搭建和RestFul风格接口
- 邮箱回执怎么看_考研复试联系导师邮件怎么写?
- 【NOIP2018】【Luogu5019】铺设道路(贪心,差分)
- vue、react等单页面项目应该这样子部署到服务器
- 如何在 iPhone 和 iPad 上快速找到合适照片?
- JAVA锁和volatile的内存语义volatile的使用场景
- ASP.NET Core 源码阅读笔记(3) ---Microsoft.AspNetCore.Hosting
- 计算机网络实验指导书 pdf,计算机网络实验指导书(新版).pdf
- 如何在WPS2000中插入AutoCad图形文件(转)
- 围棋AI kataGo下载
- 计算机控制技术第二版答案于微波,微波技术习题答案 2.doc
- AR智能眼镜tooz DevKit 20初体验
- PgSQL——学习笔记七: LIKE 子句:获取包含某些字符的数据 LIMIT 子句:限制 SELECT 语句中查询的数据的数量
- jmeter如何定位网络延时_JMeter 如何模拟不同的网络速度
- 瓦伦达效应:在大是大非面前不要在乎结果所带来的后果,你就会成功!
- [BZOJ2754]-[SCOI2012]喵星球上的点名-AC自动机+树状数组