七、前端开发-JavaScript HTTP

七、前端开发语言体系-JavaScript HTTP

JavaScript AJAX

AJAX简介

AJAX = Asynchronous JavaScript And XML.

AJAX 不是编程语言,它仅仅组合了:

  • 浏览器内建的 XMLHttpRequest 对象(从 web 服务器请求数据)
  • JavaScript 和 HTML DOM(显示或使用数据)

Ajax 允许通过与场景后面的 Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面。

AJAX工作流程:

  1. 网页中发生一个事件(页面加载、按钮点击)
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送请求
  4. 服务器处理该请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 执行正确的动作(比如更新页面)

ajax

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": "张三",
})

运行代码之后,浏览器会弹窗提示:
jsonp

其实 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
})

注意:

  1. 一定要在 json文件中用函数名+()套住
  2. 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引擎提供,不用自己部署。

  1. resolve 作用是将Promise对象状态由“未完成”变为“成功”,也就是Pending -> Fulfilled,在异步操作成功时调用,并将异步操作的结果作为参数传递出去。
  2. reject 作用是将Promise对象状态由“未完成”变为“失败”,也就是Pending -> Rejected,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
//创建 Promise 实例
var promise = new Promise(function(resolve, reject){
    // ... some code
    
    if (/* 异步操作成功 */) {
        resolve(value);
    } else {
        reject(error);
    }
})

Promise 对象有一个比较常用的 then 方法,用来执行回调函数。then 方法可以接受两个回调函数作为参数。

  1. Promise对象状态改为Resolved时调用 (必选)
  2. 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:

  1. Promise.then( )
  2. Promise.catch( ):发生错误的回调函数
  3. Promise.all( ):所有的对象都有完成,相当于“且”。适合用于所有对象的结果都完成了才去执行then()成功的操作
  4. Promise.race( ):其中一个对象完成即可,相当于“或”。同时执行多个实例,只要有一个实例改变状态,Promise就改为那个实例所改变的状态
  5. Promise.resolve( ):将现有对象转为 Promise 对象,状态为 resolved
  6. 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

参考文章

W3School-JavaScript AJAX

javascript中ajax的四大步骤

js—JSONP原理及使用

【JavaScript】通过封装自己的JSONP解决浏览器的跨域问题(Ajax跨域)

JS执行——Promise - 简书

js promise看这篇就够了

发布了61 篇原创文章 · 获赞 25 · 访问量 7202

猜你喜欢

转载自blog.csdn.net/qq_42582489/article/details/104309083