七、前端开发语言体系-JavaScript HTTP
文章目录
JavaScript AJAX
AJAX简介
AJAX = Asynchronous JavaScript And XML.
AJAX 不是编程语言,它仅仅组合了:
- 浏览器内建的 XMLHttpRequest 对象(从 web 服务器请求数据)
- JavaScript 和 HTML DOM(显示或使用数据)
Ajax 允许通过与场景后面的 Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面。
AJAX工作流程:
- 网页中发生一个事件(页面加载、按钮点击)
- 由 JavaScript 创建 XMLHttpRequest 对象
- XMLHttpRequest 对象向 web 服务器发送请求
- 服务器处理该请求
- 服务器将响应发送回网页
- 由 JavaScript 读取响应
- 由 JavaScript 执行正确的动作(比如更新页面)
AJAX-XMLHttp
Ajax 的核心是 XMLHttpRequest 对象。
所有现代浏览器(Chrome、IE7+、Firefox、Safari 以及 Opera)都支持 XMLHttpRequest 对象。XMLHttpRequest 对象用于同幕后服务器交换数据。这意味着可以更新网页的部分,而不需要重新加载整个页面。
创建 XMLHttpRequest 对象的语法是:
variable = new XMLHttpRequest();
因为IE5、IE6使用的是 ActiveX 对象,为了应对所有浏览器,请检查浏览器是否支持 XMLHttpRequest 对象。如果支持,创建 XMLHttpRequest 对象,如果不支持,则创建 ActiveX 对象。
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
}
else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
出于安全原因,现代浏览器不允许跨域访问。这意味着尝试加载的网页和 XML 文件都必须位于相同服务器上。
如果您希望在自己的页面上使用以上实例,那么您所加载的 XML 文件必须位于您自己的服务器上。
XMLHttpRequest 对象常用的方法和属性:
方法 | 描述 | 属性 | 描述 |
---|---|---|---|
new XMLHttpRequest() | 创建新的 XMLHttpRequest 对象 | onreadystatechange | 定义当 readyState 属性发生变化时被调用的函数 |
getAllResponseHeaders() | 返回头部信息 | readyState | 保存 XMLHttpRequest 的状态,从0-4变化。0:请求未初始化,1:服务器连接已建立,2:请求已收到,3:正在处理请求,4:请求已完成且响应已就绪 |
open(method, url, async) | 规定请求的类型、URL和是否异步处理请求。method:请求类型 GET 或 POST,url:文件位置,async:true(异步)或 false(同步) | responseText | 以字符串返回响应数据 |
send() | 将请求发送到服务器,用于 GET 请求 | responseXML | 以 XML 数据返回响应数据 |
send(string) | 将请求发送到服务器,用于 POST 请求 | status | 返回请求的状态号。200: “OK”,404: “Not Found” |
setRequestHeader(header, value) | 向要发送的报头添加标签/值对。header:规定头部名称,value:规定头部值 | statusText | 返回状态文本(例如 “OK” 或 “Not Found”) |
AJAX请求
向服务器发送请求,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法。
至于请求类型使用 GET 还是 POST,一般我们使用 GET,因为 GET 比 POST 更简单更快速,适用于绝大多数场景。
不过,请在以下情况始终使用 POST:
- 缓存文件不是选项(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 无大小限制)
- 发送用户输入(可包含未知字符),POST 比 GET 更强大更安全
一条简单的 GET 请求:
xhttp.open("GET", "demo_get.asp", true);
xhttp.send();
一条简单的 POST 请求:
xhttp.open("POST", "demo_post.asp", true);
xhttp.send();
open( ) 方法的 url 参数,是服务器上文件的地址。该文件可以是任何类型的文件,如 .txt 和 .xml,或服务器脚本文件,如 .asp 和 .php(它们可以在发送回响应之前在服务器执行操作)。
xhttp.open("GET", "ajax_test.asp", true);
open( ) 方法的 async 参数设置为 true 表示异步发送请求。通过异步发送,JavaScript 不必等待服务器响应,可以在等待服务器响应时执行其他脚本,当响应就绪时处理响应。
false 表示同步发送请求,一般不推荐同步的 XMLHttpRequest,因为 JavaScript 将停止执行直到服务器响应就绪。如果服务器繁忙或缓慢,应用程序将挂起或停止。
xhttp.open("GET", "ajax_test.asp", true);
通过 XMLHttpRequest 对象,我们可以定义当请求接收到应答时所执行的函数。
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
AJAX响应
- readyState 属性存留 XMLHttpRequest 的状态。
- onreadystatechange 属性定义当 readyState 发生变化时执行的函数。
- status 属性和 statusText 属性存有 XMLHttpRequest 对象的状态。
每当 readyState 发生变化时就会调用 onreadystatechange 函数。
//当 readyState 为 4,status 为 200 时,响应就绪
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
回调函数是一种作为参数被传递到另一个函数的函数。
如果您的网站中有多个 AJAX 任务,那么您应该创建一个执行 XMLHttpRequest 对象的函数,以及一个供每个 AJAX 任务的回调函数。该函数应当包含 URL 以及当响应就绪时调用的函数。
loadDoc("url-1", myFunction1);
loadDoc("url-2", myFunction2);
function loadDoc(url, cFunction) {
var xhttp;
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
cFunction(this);
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
function myFunction1(xhttp) {
// action goes here
}
function myFunction2(xhttp) {
// action goes here
}
- getAllResponseHeaders() 方法返回所有来自服务器响应的头部信息。
- getResponseHeader() 方法返回来自服务器响应的特定头部信息。
document.getElementById("demo").innerHTML = this.getAllResponseHeaders();
document.getElementById("demo").innerHTML = this.getResponseHeader("Last-Modified");
JavaScript JSONP
JSONP简介
注意 JSONP 和 JSON 不一样,这里先提一下 JSON 的概念。
JSON是一种轻量级的数据传输格式,被广泛应用于当前Web应用中。JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进行数据的传输。
为了保证用户访问的安全,现代浏览器使用了同源策略,不允许访问非同源的页面,即不允许跨域访问。如果两个页面中的协议、域名、端口、子域名任意有一项不同,两者之间所进行的访问行动就是跨域的。
ajax跨域只是属于浏览器”同源策略”中的一部分,这里我们仅讨论 ajax 跨域问题。解决 ajax 跨域常用的有两个方式:
- JSONP方式
- CORS方式
JSONP(JSON Padding) 是 JSON 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。JSONP 并不是 JSON,它是为了解决跨域请求而提出的概念。
CORS 与 JSONP的使用目的相同,但是比 JSONP 更强大。CORS需要浏览器和服务器同时支持。目前,所有主流浏览器都支持该功能,IE浏览器不能低于IE10。
JSONP 只支持 GET 请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。
想对 CORS 进行详细探究的请参考这篇博客 跨域资源共享 CORS 详解,这里我们着重介绍 JSONP。
JSONP原理
因为 script 标签 src 属性中的链接却可以访问跨域的 JS 脚本,所以我们利用 script 标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。
当需要通讯时,本站脚本创建一个 script 元素,地址指向第三方的API网址,并创建一个回调函数(callback)来接收数据。第三方产生的响应是 JSON 数据的包装(即JSONP),这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。
JSONP具体实现
动态的添加了一个 script 标签, src 指向跨域的一个 php 脚本,并且将 js 函数名作为 callback 参数传入。
//前端代码
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript" src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js">
</script>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript">
$(document).ready(function(){
var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonhandle";
var obj = $('<script><\/script>');
obj.attr("src",url);
$("body").append(obj);
});
</script>
</body>
</html>
//PHP代码
<?php
$data = array(
'age' => 20,
'name' => '张三',
);
$callback = $_GET['callback'];
echo $callback."(".json_encode($data).")";
return;
?>
PHP代码返回了一段JS语句,即
jsonhandle({
"age" : 15,
"name": "张三",
})
运行代码之后,浏览器会弹窗提示:
其实 jQuery 提供了方便使用 JSONP 的方式,推荐使用这一种方式:
<!DOCTYPE html>
<html>
<head>
<title>JSONP</title>
<meta charset="utf-8">
<script type="text/javascript" src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>
</head>
<body>
<p>JSONP测试跨域</p>
<p id="ceshi"></p>
<script type="text/javascript">
function demo(data){
document.getElementById("ceshi").innerHTML = data.name+" is "+data.age+" age";
}
</script>
<script src="test.json?callback=demo"></script>
</body>
</html>
test.json文件与 html文件在同一目录下
demo(
{
"name":"Bob",
"age":23
})
注意:
- 一定要在 json文件中用函数名+()套住
- js中的回调函数一定要与 json中函数名相同
JavaScript Promise
Promise简介
JavaScript是单线程语言,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。
但是过多的回调会导致“回调地狱”,代码既不美观,也不易维护,所以就有了Promise。
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。它最早由社区提出并实现,ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。
Promise特点
Promise 是一个对象,是用来处理异步操作的。Promise 顾名思义为承诺、许诺的意思,意思是使用了 Promise 之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复。
Promise 对象一共有三种状态,对象的状态不受外界影响,一旦状态改变就不会再变。
- Pending 状态(进行中)
- Fulfilled 状态(已成功)
- Rejected 状态(已失败)
Promise 的过程一般只有两种:
- Pending -> Fulfilled
- Pending -> Rejected
Promise 优缺点
优点 | 缺点 |
---|---|
解决回调 | 无法监测进行状态 |
链式调用 | 新建立即执行且无法取消 |
减少嵌套 | 内部错误无法抛出 |
如果对“链式调用”不清楚的,请参考这篇博客 链式调用方法的实现原理和方法
Promise用法
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。
- resolve 作用是将Promise对象状态由“未完成”变为“成功”,也就是Pending -> Fulfilled,在异步操作成功时调用,并将异步操作的结果作为参数传递出去。
- reject 作用是将Promise对象状态由“未完成”变为“失败”,也就是Pending -> Rejected,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
//创建 Promise 实例
var promise = new Promise(function(resolve, reject){
// ... some code
if (/* 异步操作成功 */) {
resolve(value);
} else {
reject(error);
}
})
Promise 对象有一个比较常用的 then 方法,用来执行回调函数。then 方法可以接受两个回调函数作为参数。
- Promise对象状态改为Resolved时调用 (必选)
- Promise对象状态改为Rejected时调用 (可选)
let promise = new Promise(function(resolve, reject){
console.log("AAA");
resolve()
});
promise.then(() => console.log("BBB"));
console.log("CCC")
// 输出顺序为:AAA CCC BBB
执行后,我们发现输出顺序总是 AAA -> CCC -> BBB。这是因为,在 Promise 新建后会立即执行,所以首先输出 AAA。然后,then 方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行,所以 会接着输出 CCC,最后输出 BBB。
Promise 与定时器混用:
let promise = new Promise(function(resolve, reject){
console.log("1");
resolve();
});
setTimeout(()=>console.log("2"), 0);
promise.then(() => console.log("3"));
console.log("4");
// 输出为:1 4 3 2
1与4的顺序不必再说,而2与3先输出Promise的then,而后输出定时器任务。原因则是Promise属于JavaScript引擎内部任务,而setTimeout则是浏览器API,而引擎内部任务优先级高于浏览器API任务,所以有此结果。
Promise 常用API:
- Promise.then( )
- Promise.catch( ):发生错误的回调函数
- Promise.all( ):所有的对象都有完成,相当于“且”。适合用于所有对象的结果都完成了才去执行then()成功的操作
- Promise.race( ):其中一个对象完成即可,相当于“或”。同时执行多个实例,只要有一个实例改变状态,Promise就改为那个实例所改变的状态
- Promise.resolve( ):将现有对象转为 Promise 对象,状态为 resolved
- Promise.reject( ):返回一个 Promise 对象,状态为 rejected
let p1 =new Promise(function(resolve,reject){
resolve(1);
});
let p2 = new Promise(function(resolve,reject){
resolve(2);
});
let p3 = new Promise(function(resolve,reject){
resolve(3);
});
Promise.all([p1, p2, p3]).then(function (results) {
console.log('success:'+results);
}).catch(function(r){
console.log("error");
console.log(r);
});
//输出为:success:1,2,3