简介

浏览器与服务器之间采用 HTTP 协议通信,用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出 HTTP 请求。

1999年,微软公司发布 IE 浏览器5.0版,第一次引入新功能:允许 JavaScript 脚本向服务器发起 HTTP 请求。这个功能当时并没有引起注意,直到2004年 Gmail 发布和2005年 Google Map 发布,才引起广泛重视。

2005年2月,Ajax (Asynchronous JavaScript and XML) 这个词第一次正式提出,指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。W3C 在2006年发布了它的国际标准。

XMLHTML 类似,都是一种基于标签的标记语言,不过 XML 没有预定义标签,一般用来存储数据。现在 XML 格式已经过时了,服务器返回的都是 JSON 格式的数据,AJAX 这个词的字面含义已经消失了,但它已成为 JavaScript 脚本发起 HTTP 通信的代名词,也就是说,只要用脚本发起通信,就可以叫做 AJAX 通信。

Ajax 的优点包括:

  • 允许只更新一个 HTML 页面的部分 DOM,而无须重新加载整个页面
  • 允许异步工作,这意味着当网页的一部分正试图重新加载时,您的代码可以继续运行(相比之下,同步会阻止代码继续运行,直到这部分的网页完成重新加载)。

存在的问题包括:

  • 没有浏览历史(无法后退)
  • 存在跨域问题(A网站向B网站发送内容)
  • 对SEO优化不友好

通过交互式网站和现代 Web 标准,AJAX 正在逐渐被 JavaScript 框架中的函数和官方的 Fetch API 标准取代

Ajax 通过 xhr 对象实现,实现步骤为:

// 1. 创建 XMLHttpRequest 实例
const xhr = new XMLHttpRequest()
// 2. 发出 HTTP 请求
xhr.open('GET', 'http://127.0.0.1:3000/server?page=1')
xhr.send()
// 3. 接收服务器传回的数据
xhr.onreadystatechange = () => {// 4. 更新网页数据if(xhr.readyState === XMLHttpRequest.DONE || xhr.status===200) {document.getElementById('target').innerHTML = xhr.responseText}
}

XHR

XHR (XMLHttpRequest) 是一种创建 Ajax 请求的 JavaScript API。实际上 XHR 可以用于获取任何类型的数据,而不仅仅是 XML。它甚至支持 HTTP 以外的协议(包括 file://FTP),尽管可能受到更多出于安全等原因的限制。

规范:xhr.spec.whatwg.org/

构造函数 XMLHttpRequest,可以使用 new 命令生成实例,没有任何参数。

const xhr = new XMLHttpRequest()

Open & Send

生成实例后,就可以使用 open() 方法初始化一个请求

/*** method: 要使用的 HTTP 方法,比如 GET、POST、PUT、DELETE* url: 一个 DOMString 表示要向其发送请求的 URL* async: 可选,表示是否异步执行操作,默认为true* user: 可选,用户名用于认证用途;默认为 null* password: 可选,密码用于认证用途,默认为 null*/
xhr.open(method, url)
xhr.open(method, url, async)
xhr.open(method, url, async, user)
xhr.open(method, url, async, user, password)

然后使用 send() 方法发送请求

/*** body: 可选参数,默认为null* 返回值:undefined*/
XMLHttpRequest.send(body)

body 参数接受的类型包括:

  • null
  • Document 对象,在发送之前被序列化
  • XMLHttpRequestBodyInit
type XMLHttpRequestBodyInit = Blob | BufferSource | FormData | URLSearchParams | string;

异常情况:

  • InvalidStateErrorsend() 方法已经被调用但该请求还未结束
  • NetworkError:请求发送资源类型是 Blob,但请求方法不是 GET

请求头

setRequestHeader()

用于设置浏览器发送的 HTTP 请求的头信息。该方法必须在 open() 之后、send() 之前调用。如果该方法多次调用,设定同一个字段,则每一次调用的值会被合并成一个单一的值发送。

xhr.setRequestHeader('Content-Type', 'application/json')
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length)
xhr.send(JSON.stringify(data))

getResponseHeader()

返回响应指定字段的值,如果还没有收到服务器回应或者指定字段不存在则返回 null,该方法的参数不区分大小写,如果有多个字段同名,它们的值会被连接为一个字符串,每个字段之间使用“逗号+空格”分隔

getAllResponseHeaders()

返回一个字符串,表示服务器发来的所有 HTTP 头信息。格式为字符串,每个头信息之间使用 CRLF 分隔(回车+换行),如果没有收到服务器回应,该属性为 null。如果发生网络错误,该属性为空字符串。

date: Fri, 08 Dec 2017 21:04:30 GMT\r\n
content-encoding: gzip\r\n
x-content-type-options: nosniff\r\n
server: meinheld/0.6.1\r\n
x-frame-options: DENY\r\n
content-type: text/html; charset=utf-8\r\n
connection: keep-alive\r\n
strict-transport-security: max-age=63072000\r\n
vary: Cookie, Accept-Encoding\r\n
content-length: 6502\r\n
x-xss-protection: 1; mode=block\r\n

withCredentials

XMLHttpRequest.withCredentials 属性是一个布尔值,表示跨域请求时,用户信息(比如 Cookie 和认证的 HTTP 头信息)是否会包含在请求之中,默认为false,即向 example.com 发出跨域请求时,不会发送 example.com 设置在本机上的 Cookie(如果有的话)。

xhr.open('GET', 'http://example.com/', true)
xhr.withCredentials = true
xhr.send(null)

为了让这个属性生效,服务器必须显式返回 Access-Control-Allow-Credentials 头信息

Access-Control-Allow-Credentials: true

withCredentials 属性打开的话,跨域请求不仅会发送 Cookie,还会设置远程主机指定的 Cookie。反之也成立,如果 withCredentials 属性没有打开,那么跨域的 AJAX 请求即使明确要求浏览器设置 Cookie,浏览器也会忽略。

注意,脚本总是遵守同源政策,无法从 document.cookie 或者 HTTP 回应的头信息之中,读取跨域的 CookiewithCredentials 属性不影响这一点。

如果需要跨域 AJAX 请求发送 Cookie,需要 withCredentials 属性设为 true。注意,同源的请求不需要设置这个属性。

状态监听

一个 XHR 实例当前所处的状态可以通过 readyState 属性获取

状态 描述
0 UNSENT 对象被创建,但尚未调用 open() 方法
1 OPENED open() 方法已经被调用
2 HEADERS_RECEIVED send() 方法已经被调用,并且头部和状态可读取
3 LOADING 加载中,responseText 属性已经包含部分数据
4 DONE 加载操作已完成

通信过程中,每当实例对象发生状态变化,它的 readyState 属性的值就会改变。这个值每一次变化,都会触发 readyStateChange 事件。XMLHttpRequest.onreadystatechange 属性指向一个监听函数,readystatechange 事件发生时,就会执行这个属性。

xhr.onreadystatechange = () => {if (xhr.readyState === 4) { } // 请求结束,处理服务器返回的数据else { } // 显示提示 加载中...
}

另外,如果调用实例的 abort() 方法将终止请求,也会造成 readyState 属性变化

事件监听

XHR 对象还继承了 XMLHttpRequestEventTarget 接口定义的事件相关属性

属性 事件类型 描述
onloadstart loadstart 开始加载
onload load 请求结束,数据加载完毕
onloadend loadend 请求结束,状态未知在触发 errorabortload 事件之后
onprogress progress 请求接收到数据的时候被周期性触发
onabort abort 请求终止
onerror error 请求遇到错误
ontimeout timeout 当进度由于预定时间到期而终止

进度

上传文件时,通过 XMLHttpRequest.upload 属性可以得到一个 upload 对象

interface XMLHttpRequest extends XMLHttpRequestEventTarget {readonly upload: XMLHttpRequestUpload;
}interface XMLHttpRequestUpload extends XMLHttpRequestEventTarget {}

XMLHttpRequestUpload 接口同样继承了 XMLHttpRequestEventTarget 接口,通过监听其 progress 事件,可以周期性的监听上传的进度

const upload = xhr.upload
upload.addEventListener('progress', (evt) => {if (evt.lengthComputable) {const percentComplete = evt.loaded / evt.total;}
})

超时

XMLHttpRequest.timeout 属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性等于 0,就表示没有时间限制。

xhr.timeout = 10 * 1000 // 指定 10 秒钟超时
xhr.ontimeout = () => {console.error('请求超时')
}

中断

除了超时自动请求外,可以调用 XMLHttpRequest.abort() 方法主动中断请求

xhr.abort()
xhr.onabort = () => {console.log('请求已中断')
}

响应处理

Status

XMLHttpRequest.status 属性返回一个整数,表示服务器回应的 HTTP 状态码。XMLHttpRequest.statusText 属性返回一个字符串,表示服务器发送的状态提示。

status statusText 描述
200 OK 访问正常
301 Moved Permanently 永久移动
302 Move temporarily 暂时移动
304 Not Modified 未修改
307 Temporary Redirect 暂时重定向
401 Unauthorized 未授权
403 Forbidden 禁止访问
404 Not Found 未发现指定网址
500 Internal Server Error 服务器发生错误

基本上,只有 2xx304 的状态码,表示服务器返回是正常状态

if (xhr.readyState === 4) {if ((xhr.status >= 200 && xhr.status < 300) || (xhr.status === 304)) {// 处理服务器的返回数据} else {// 出错}
}

Response

XHR 实例表达响应数据相关的属性包括:

1.response

响应的正文。返回的类型为 ArrayBufferBlobDocumentJavaScript ObjectDOMString 中的一个,这取决responseType 属性。

2.responseType

一个枚举字符串值,用于指定响应中包含的数据类型,可以采用以下值:

  • 空字符串:与默认类型 text 相同
  • arraybuffer: 包含二进制数据的 JavaScript ArrayBuffer
  • blob: 包含二进制数据的 Blob 对象
  • document: 根据接收到的数据的 MIME 类型而定, HTML DocumentXML XMLDocument
  • json: 通过将接收到的数据内容解析为 JSON 而创建的 JavaScript 对象
  • text: DOMString 对象中的文本

responseType 设置为特定值时,应确保服务器实际发送的响应与该格式兼容。如果服务器返回的数据与设置的 responseType 不兼容,则 response 的值将为null

3.responseText

在一个请求被发送后,从服务器端返回的纯文本的值,为 null 时,表示请求失败了,为空字符串时,表示这个请求还没有被 send()

4.reponseURL

返回响应的序列化 URL,如果 URL 为空则返回空字符串。如果 URL 有锚点,则位于 URL # 后面的内容会被删除。如果 URL 有重定向,responseURL 的值会是经过多次重定向后的最终 URL

5.responseXML

XMLHttpRequest 中收到的 HTML 节点或解析后的 XML 节点,也可能是在没有收到任何数据或数据类型错误的情况下返回的 null

如果服务器没有明确指出 Content-Type 头是 text/xml 还是 application/xml, 可以使用 XMLHttpRequest.overrideMimeType() 强制 XMLHttpRequest 解析为 XML

overrideMimeType()

XMLHttpRequest.overrideMimeType() 方法用来指定 MIME 类型,覆盖服务器返回的真正的 MIME 类型,从而让浏览器进行不一样的处理。该方法必须在 send() 方法之前调用。

正常情况下应该使用 responseType 属性告诉服务器返回指定类型的数据,只有在服务器无法返回某种数据类型时,才使用 overrideMimeType() 方法。

typescript 声明参考

typescript/lib/lib.dom.d.ts

XMLHttpRequestEventTarget

/** * 度量一个正在进行的过程的事件接口:* 1. HTTP请求 * 2. 加载 <img>, <audio>, <video>, <style> 或 <link>*/
interface ProgressEvent<T extends EventTarget = EventTarget> extends Event {readonly lengthComputable: boolean;readonly loaded: number;readonly target: T | null;readonly total: number;
}/*** XMLHttpRequest事件类型*/
interface XMLHttpRequestEventTargetEventMap {"abort": ProgressEvent<XMLHttpRequestEventTarget>;"error": ProgressEvent<XMLHttpRequestEventTarget>;"load": ProgressEvent<XMLHttpRequestEventTarget>;"loadend": ProgressEvent<XMLHttpRequestEventTarget>;"loadstart": ProgressEvent<XMLHttpRequestEventTarget>;"progress": ProgressEvent<XMLHttpRequestEventTarget>;"timeout": ProgressEvent<XMLHttpRequestEventTarget>;
}/*** XMLHttpRequest事件类型对应的属性接口*/
interface XMLHttpRequestEventTarget extends EventTarget {onabort: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;onerror: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;onload: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;onloadend: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;onloadstart: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;onprogress: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;ontimeout: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null;addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;removeEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void;removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}/*** XMLHttpRequest事件对象的构造函数*/
declare var XMLHttpRequestEventTarget: {prototype: XMLHttpRequestEventTarget;new(): XMLHttpRequestEventTarget;
};

XHR

type XMLHttpRequestBodyInit = Blob | BufferSource | FormData | URLSearchParams | string;type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "json" | "text";/*** XMLHttpRequest事件类型*/
interface XMLHttpRequestEventMap extends XMLHttpRequestEventTargetEventMap {"readystatechange": Event;
}/** * 使用 XMLHttpRequest (XHR) 对象和服务器进行交互* 1. 在不刷新整个页面的情况下从一个URL获取数据* 2. 网页部分更新而不阻断用户的操作*/
interface XMLHttpRequest extends XMLHttpRequestEventTarget {onreadystatechange: ((this: XMLHttpRequest, ev: Event) => any) | null;/** 请求客户端的状态 */readonly readyState: number;/** 响应体 */readonly response: any;/** * 响应体的文本形式 * 如果responseType为空字符串或text的时候抛出 InvalidStateError 错误 */readonly responseText: string;/** * 响应体的类型 * 1. 空字符串(default) * 2. arraybuffer * 3. blob * 4. document * 5. json * 6. text * * 全局对象不是window的时候,设置为 document将被忽略 * 请求在加载中或已完成时设置抛出 InvalidStateError * 同步请求且当前全局对象不是window时抛出 InvalidAccessError */responseType: XMLHttpRequestResponseType;readonly responseURL: string;/** * document 形式的响应 * 当responseType不为空字符串或document的时候抛出 InvalidStateError */readonly responseXML: Document | null;readonly status: number;readonly statusText: string;/** * 毫秒为单位 * 设置为非0值会在指定时间结束后终止请求 * 指定时间结束后,请求未完成且非异步请求,timeout事件被触发,或者send()方法抛出 TimeoutError * 同步请求且当前全局对象不是window时抛出 InvalidAccessError */timeout: number;/**  * 返回一个关联的XMLHttpRequestUpload对象 * 用于获取文件传输过程中的信息 */readonly upload: XMLHttpRequestUpload;/** * True when credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false. * * When set: throws an "InvalidStateError" DOMException if state is not unsent or opened, or if the send() flag is set. */withCredentials: boolean;/** 中止网络请求 */abort(): void;getAllResponseHeaders(): string;getResponseHeader(name: string): string | null;/** * Sets the request method, request URL, and synchronous flag. * * Throws a "SyntaxError" DOMException if either method is not a valid method or url cannot be parsed. * * Throws a "SecurityError" DOMException if method is a case-insensitive match for `CONNECT`, `TRACE`, or `TRACK`. * * Throws an "InvalidAccessError" DOMException if async is false, current global object is a Window object, and the timeout attribute is not zero or the responseType attribute is not the empty string. */open(method: string, url: string | URL): void;open(method: string, url: string | URL, async: boolean, username?: string | null, password?: string | null): void;/** * Acts as if the `Content-Type` header value for a response is mime. (It does not change the header.) * Throws an "InvalidStateError" DOMException if state is loading or done. */overrideMimeType(mime: string): void;/** * 初始化请求 * 当请求方式为GET或HEAD时忽略body参数 * Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set. */send(body?: Document | XMLHttpRequestBodyInit | null): void;/** * Combines a header in author request headers. * Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set. * Throws a "SyntaxError" DOMException if name is not a header name or if value is not a header value. */setRequestHeader(name: string, value: string): void;readonly DONE: number;readonly HEADERS_RECEIVED: number;readonly LOADING: number;readonly OPENED: number;readonly UNSENT: number;addEventListener<K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;removeEventListener<K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}/*** XMLHttpRequest 构造函数*/
declare var XMLHttpRequest: {prototype: XMLHttpRequest;new(): XMLHttpRequest;readonly DONE: number;readonly HEADERS_RECEIVED: number;readonly LOADING: number;readonly OPENED: number;readonly UNSENT: number;
};

upload 属性对应的接口定义

interface XMLHttpRequestUpload extends XMLHttpRequestEventTarget {addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;removeEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void;removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}declare var XMLHttpRequestUpload: {prototype: XMLHttpRequestUpload;new(): XMLHttpRequestUpload;
};

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

前端工程化之模块化基础相关推荐

  1. 对前端工程化、模块化、组件化开发的理解

    参考理解一: 提到前端往往很多人的映像就是入门简单,HTML.CSS加一起一个星期基本上就能大概上手,JS难一点但也能很快写一些简单的小效果,在网上随便一搜索各种特效代码随意用,一个新手前端也能在很短 ...

  2. 前端工程化概述||模块化相关规范

    前端工程化 模块化概述 浏览器端模块化规范 服务器端模块化规范 大一统的模块化规范 – ES6模块化 ① npm install --save-dev @babel/core @babel/cli @ ...

  3. 前端工程化和模块化学习资料汇总

    2019独角兽企业重金招聘Python工程师标准>>> 1.我为什么这么强调前端工程化 2.前端工程 3.前端优化带来的思考,浅谈前端工程化 4.前端模块化 5.我的前端之路:工具化 ...

  4. 前端工程化、模块化、组件化

    工程化     前端工程化是一种高层次思想而不是某种技术,所谓前端工程化就是将前端项目当成一项系统工程进行分析.组织和构建从而达到项目结构清晰.分工明确.团队配合默契.开发效率提高的目的.而模块化和组 ...

  5. 前端工程化、模块化方案教程大全,现代前端高手进阶必经之路(欢迎收藏)...

    关注掘金和github很久了,但是一直没有在上面发表什么文章,这次静下心来写了个前端的目前工程化与模块化方案的总结,后期会继续更新,为开源社区做出更大贡献. 前端的模块化方案从早年的require.j ...

  6. 浅谈前端工程化、模块化、组件化

    1.前端工程化,是一种思维而不是技术.前端工程化就是用做工程的思维来开发自己的项目,而不是一个页面接着一个页面来开发. 2.前端模块化,前端工程化是一个高层次的思维,而模块化和组件化是在工程化思维下相 ...

  7. 前端工程化----Node.js基础篇

    文章目录 1.认识Node.js Node.js是什么 Node.js应用场景 2.Node.js安装和版本管理 Node.js安装 Node.js版本工具 3.Node.js执行文件 4.Node. ...

  8. altium designer无法创建工程_前端工程化之开发脚手架及封装自动化构建

    工程化笔记 .  . 光 前端工程化简述 简述 一切能提升前端开发效率,提高前端应用质量的手段和工具都是前端工程化. 模块化,组件化,规范化,自动化. 解决的问题 传统语言或语法的弊端. 无法使用模块 ...

  9. 前端类名优秀命名例子_这是一篇需要花费你15分钟阅读的干货!浅谈前端工程化...

    01前端工程化的背景 随着业务的扩展.业务需求更加复杂.项目团队的壮大以及项目的增多等.制定一套适用于团队的前端工程化方案很有必要. 02前端工程化是什么 前端工程化是一个很广泛的话题.涉及的技术与解 ...

最新文章

  1. 【实战经验分享】一劳永逸的解决网线随意热插拔问题
  2. 三点到六点是几个小时_你被“8小时睡眠论”给骗了吗?!
  3. ajax创建对象,ajax创建对象
  4. html5 页面 参数传递,详解html中页面跳转传递参数的问题
  5. [JLOI2014]松鼠的新家
  6. python入门代码大全-python入门代码指南教程书籍推荐2020总结全集汇总
  7. MATLAB怎么输入无穷小,matlab如何输入代码
  8. ideaIU-2017.3.4安装破解图文教程详细步骤
  9. 吃鸡游戏计算机配置,手游吃鸡pc端吃什么配置
  10. 因为和同事交心,最终辞职了
  11. 荐读 | 从公有链到生态架构者,Conflux 做了些什么?
  12. 入门php学习 -- 学生信息系统
  13. 追寻绿色世界、草木清香
  14. XSCTF联合招新【真是阳间题】(MSIC+Crypto)
  15. html如何做成弹窗,js+html+css制作弹窗
  16. 全国计算机高新技术bim应用等级,BIM有等级考试吗?BIM等级考试有几种形式?
  17. 无所适从不是为了颓废
  18. TRIZ创新方法——How-to模型与知识效应库
  19. R语言差异检验:单因素方差分析
  20. android+实现微信对话框样式,实现微信对话框的图片样式

热门文章

  1. 【机械】基于matlab模拟打桩机运动学仿真附matlab代码
  2. 第一章项目学习活动记录表
  3. vue2安装axios基本配置
  4. 马文蔚物理学第6版配套题库 课后答案
  5. mdb java_java从mdb文件中读出数据
  6. 【Codeforces 723D】Lakes in Berland (dfs)
  7. 004-PBR历史和概念
  8. 莫烦pytorch CNN卷积神经网络
  9. XML文件生成XSD文件的方法
  10. spring-retry简单用法