同步和异步
概念
同步:必须等待前面的任务完成,才能继续后面的任务。
异步:不受当前任务的影响。
异步更新网站
我们在访问一个普通的网站时,当浏览器加载完HTML、CSS、JS
以后,网站的内容就固定了。如果想让网站内容发生更改,就必须刷新页面才能够看到更新的内容。
可如果用到异步更新,情况就大为改观了。比如,我们在访问新浪微博时,看到一大半了,点击底部的加载更多,会自动帮我们加载更多的微博,同时页面并没有刷新。
试想一下,如果没有异步刷新的话,每次点击“加载更多”,网页都要刷新,体验就太不好了。
web
前端里的异步更新,就要用到 Ajax
。
Ajax
概念
Ajax
(Asynchronous Javascript And XML
:异步 JavaScript
和 XML
)。它是对于现有技术的结合。Ajax
的核心是 js
对象:XMLHttpRequest
。也就是使用 XMLHttpRequest
对象与服务器通信。 它可以使用 JSON,XML,HTML
和 text
文本等格式发送和接收数据。
在浏览器中,我们可以在不刷新页面的情况下,通过ajax
的方式与服务器通信,交换数据,或更新页面,去获取一些新的内容。
XMLHttpRequest
对象详解
创建异步对象
var xhr;
if (window.XMLHttpRequest) {
// Mozilla, Safari, IE7+ ...
hr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// IE 6 and older
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
发送请求
发送请求的方法:
// method:请求的类型;GET 或 POST;url:文件在服务器上的位置;async:true(异步)或 false(同步)
open(method, url, async);
GET
请求
xhr.open('get', '请求的url');
xhr.send();
POST
请求
如果想让 像form
表单提交数据那样使用POST
请求,就需要使用 XMLHttpRequest
对象的 setRequestHeader()
方法 来添加 HTTP
头。然后在 send()
方法中添加想要发送的数据:
xhr.open('post', '请求的url', true);
xhr.setRequestHeader('Content-type', 'application/x-wwww-form-urlencoded');
xhr.send('name=tom&age=18');
onreadystatechange
事件
注册 onreadystatechange
事件后,每当 readyState
属性改变时,就会调用 onreadystatechange
函数。
xhr.onreadystatechange = function () {
// Process the server response here.
};
readyState
状态
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
status
状态
200: “OK”。
404: 未找到页面。
在 onreadystatechange
事件中,当 readyState
等于 4,且状态码为200时,表示响应已就绪。
服务器响应的内容
responseText
:获得字符串形式的响应数据。responseXML
:获得XML
形式的响应数据。
如果响应的是普通字符串,就使用responseText
;如果响应的是XML
,使用responseXML
。
发送 Ajax 请求的五个步骤
(1)创建异步对象。即 XMLHttpRequest
对象。
(2)使用open
方法设置请求的参数。open(method, url, async)
(请求的方法、请求的url、是否异步)。
(3)发送请求。
(4)注册事件。 注册onreadystatechange
事件,状态改变时就会调用。如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。
(5)获取返回的数据。
Ajax
请求实例
GET
请求示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax的get请求</title>
</head>
<body>
<h1>发送get请求</h1>
<input type="button" value="发送get请求" id="getAjax">
<script type="text/javascript">
document.querySelector("getAjax").onclick = function() {
// 发送ajax请求
var xhr = new XMLHttpRequest();
xhr.open('get', '请求的url');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console('数据返回成功');
console.log(xhr.responseText);
document.querySelector('h1').innerHTML = xhr.responseText;
}
}
}
</script>
</body>
</html>
POST
请求示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax的Post请求</title>
</head>
<body>
<h1>发送post请求</h1>
<input type="button" value="发送Post请求" id="postAjax">
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.open('post', '请求的url');
// 如果想要使用post提交数据,必须添加此行
xhr.setRequestHeader('Content-type', 'application/x-wwww-form-urlencoded');
// 将数据通过send方法传递
xhr.send('name=tom&age=18');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
</script>
</body>
</html>
Ajax
传输 JSON
JSON
的语法
JSON(JavaScript Object Notation)
:是ECMAScript
的子集。作用是进行数据的交换。语法更为简洁,网络传输、机器解析都更为迅速。
语法规则:
数据在键值对中
数据由逗号分隔
花括号保存对象
方括号保存数组
数据类型:
数字(整数或浮点数)
字符串(在双引号中)
逻辑值(true 或 false)
数组(在方括号中)
对象(在花括号中)
null
示例:
// 对象
{
"name":"fox",
"age":"18",
"sex":"true",
"car":null
}
// 数组
[
{
"name":"小小胡",
"age":"1"
},
{
"name":"小二胡",
"age":"2"
}
]
json 字符串 与 js 对象转换
基本所有的语言都有将 json 字符串转化为该语言对象的语法。
JS
中的转换
JSON.parse()
:将JSON
字符串转化为 js
对象。例如:
var jsObj = JSON.parse(ajax.responseText);
JSON.stringify()
:将 JS
对象转化为JSON
字符串。例如:
var Obj = {
name: "tom",
age: 18,
};
// 将 js 对象格式化为 JSON 字符串
var jsonStr = JSON.stringify(Obj);
PHP
中的转换
json_decode()
方法:将json
字符串转化为变量。json_encode()
方法:将变量转化为json
字符串。
jQuery
中的 Ajax
JQuery
作为最受欢迎的JS
框架之一,常见的Ajax
已经帮助我们封装好了,只需要调用即可。更为详细的api文档可以查阅:w3cSchool_JQueryAjax
格式:
$.ajax({
url: '请求地址',
data: 'name=tom&age=16',
type: 'POST',
// 请求成功执行的方法
success: function(argument) {},
// 在发送请求之前调用,可以做一些验证之类的处理
beforeSend: function(argument) {},
// 请求失败调用
error: function(argument) {},
})
Ajax 与 cookie
- ajax 会自动带上同源的 cookie,不会带上不同源的 cookie
- 可以通过前端设置 withCredentials 为 true, 后端设置 Header 的方式让 ajax 自动带上不同源的 cookie,但是这个属性对同源请求没有任何影响。会被自动忽略。
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com/", true);
xhr.withCredentials = true;
xhr.send(null);
Ajax函数封装
此部分把ajax发送HTTP的常用请求进行封装,方便调用,减少代码冗余,解耦合,在编写项目时可以作为工具类使用。
请求封装
// get请求封装
function getAjax(url, data) {
var xhr = new XMLHttpRequest();
if (data) {
url += '?';
url += data;
} else {}
xhr.open('get', url);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && ajax.status == 200) {
console.log(ajax.responseText);
}
}
}
// post请求封装
function postAjax(url, data) {
var xhr = new XMLHttpRequest();
xhr.open('post', url);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
if (data) {
xhr.send(data);
} else {
xhr.send();
}
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
}
// get和post一起封装
/*
参数1:url
参数2:数据
参数3:请求的方法
参数4:数据成功获取以后,调用的方法
*/
function ajaxTool(url, data, method, success) {
var xhr = new XMLHttpRequest();
// 如果忽略大小写呢
if (method == 'get') {
if (data) {
url += '?';
url += data;
} else {}
xhr.open(method, url);
xhr.send();
} else {
xhr.open(method, url);
xhr.setRequestHeader('Content-type', 'application-x-www-form-urlencoded');
if (data) {
xhr.send(data);
} else {
xhr.send();
}
}
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
success(xhr.responseText);
}
}
}
函数调用
// get请求
var resData = ajaxTool('url', 'data', 'get', function(data) {
console.log(data);
})
console.log(resData);
// post请求
var resData = ajaxTool('url', 'data', 'post', function(data) {
console.log(data);
})
console.log(resData);
同源和跨域
同源
同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同。
跨域
从我们自己的网站访问别人网站的内容,就叫跨域。
出于安全性考虑,浏览器不允许ajax跨域获取数据。
iframe
:出于安全性考虑,浏览器的开发厂商已经禁止了这种方式。JSONP
:script
标签的src
属性传递数据。
JSONP
JSONP(JSON with Padding)
:带补丁的 json
,本质是利用了 <script src=""></script>
标签具有可跨域的特性,由服务端返回一个预先定义好的JS函数的调用,并且将服务器数据以该函数参数的形式传递过来。此方法需要前后端配合完成。
html标签的 src 属性是支持跨域的:
<img src="http://xxx.com/xxx.jpg" alt="">
jsonp
就是利用这个特性实现的跨域,但用的是 script
标签。如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- jsonp 就是 利用 src,实现的跨域 用的是 script标签 -->
<script type="text/javascript" src='http://192.168.141.137/2018-02-28/myData.php'></script>
</body>
</html>
上述代码的意思是:刷新A服务器上的index
页面后,会去请求 B 服务器上的 myData.php
这个页面。而且请求的方式是get
请求。但是 B 服务器上的页面不是你想请求就可以请求的,大家一起配合才可以。
具体实现步骤:
需要首先声明的是,jsonp
只能通过 GET
方式进行请求。
(1)A客户端的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
</html>
<script type="text/javascript">
// 定义 fn() 方法
function fn(data) {
console.log('我被调用了哦');
console.log(data);
}
</script>
<!-- 使用 script标签 发送了 get请求 去到了一个 php页面 -->
<script type="text/javascript" src='http://192.168.141.137/01.php?callback1=fn'></script>
我们来分析上方代码中的最后一行的那个url:A 客户端请求的是 B服务器上的 01.php
页面。url里有个callback1=fn
,意思是:callback1是A和B 之间的约定,约定后,将执行方法 fn。
其实,fn方法已经在最后一行代码中执行了。只不过,fn方法里的data数据,是从 B 服务器中获取的。
(2)B服务器端的代码:
<?php
$mycallBack = $_GET['callback1'];
$arr = array("zhangsan","lisi","zhaoliu");
echo $mycallBack.`(`.json_encode($arr).`)`; //字符串拼接
?>
代码解释:
第一行的callback1
是A和B之间的约定,二者必须一致。
echo语句中输出的内容,即使要返回给A客户端的内容,此内容会保存在 A 客户端的fn方法的data里。 data[0]指的是 zhangsan。
json_encode
指的是,将php对象转化为 json。
刷新A页面,输出结果为:
mycallBack(["zhangsan","lisi","zhaoliu"])
jQuery 中的 JSONP
jQuery 中发送 Ajax 请求,格式是:
$("#btn").click(function(){
$.ajax({
url:"./data.php?callback1=fn",
dataType:"jsonp",
type:"get",
//jsonp:"callback1", //传递给B服务器的回调函数的名字(默认为 callback)
//jsonCallBack:"fn" //自定义的函数名称。默认为 jQuery 自动生成的随机函数名
success:function(data){
alert(data);
//$("#showInfo").html(data);
},
error:function(e){
console.log(e);
}
});
});
那如果数据是 JSONP,上方代码则改为:
$("#btn").click(function(){
$.ajax({
url:"./data.php?fn",
dataType:"text",
type:"get",
success:function(data){
alert(data);
//$("#showInfo").html(data);
},
error:function(e){
console.log(e);
}
});
});