目前,JavaScript的编程元素相比一些主流的编程语言比如C#和Java还是不算多,但是应用它的语法糖很多,如果不熟悉这些语法糖,很多的代码将难以阅读与理解,就比如同样是链式编程,在代码组织上,C#上就比JavaScript来得简明,也可能是个人习惯,觉得JavaScript以后容纳更多的编程元素后将更难以阅读,但它的发展还远没有到头,按现在的发展趋势,今后它有可能成为一流的、应对所有应用的最佳开发工具。
对于异步编程,就是通常我们俗称的AXAJ即Asynchronous Javascript And XML(异步JavaScript和XML),我们都认为它一种具体的编程技术,实质上,我们应该理解AXAJ为一系列的支持异步编程的方法、工具的集合(也可以说是一种思想),这个集合里面有很多的对象和方法来帮助我们用JavaScript语言实现异步编程,比如XMLHTTPRequest、JQuery里面的AXAJ、Promise、Fetch、Axios、async/await等等,Javascript语言本身是不支持异步编程的,但JavaScript的宿主浏览器支持,所以Javascript通过回调函数将需要异步处理的调用放到浏览器的事件循环队列,这样就实现了异步编程。
我们怎样使用JavaScript来实现异步编程的呢?
1、网页嵌套、定时器
1998年,我使用HTML + CGI开发一个Web应用,使用Web页面框架来实现局部刷新,程序提交数据时候将调用页面底部的响应而提交按钮所在的页面,这样只是底部显示变化数据【其他页面如有数据变化,这个页面的处理程序也一样可以处理】而整个页面不动。
使用定时器来实现异步编程在以前也用到过,类似在一个消息队列中不断加入消息检测,满足条件了就执行处理函数。
这些都太老旧了。
2、XMLHTTPRequest
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest</title>
</head>
<body>
<script>
//1、创建Ajax对象
let xhr=new XMLHttpRequest();
//2、设置请求信息
//xhr=open(请求方式,请求地址,是否异步)
xhr.open('Post','http://127.0.0.1/ES6_Base/ASD.php',true);
//3、配置请求完成事件
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
if(xhr.status>=200 && xhr.status<300){
let res=JSON.parse( xhr.responseText );
console.log( "用户名:"+res.Name );
console.log( "密码:"+res.Password );
}else{
console.log(xhr.status);
}
}
}
//4、发送请求
xhr.send("Name=ASD&Password=123");
</script>
</body>
</html>
PHP脚本:
<?php
$returnArr=[];//准备返回的数组
$Name = $_POST['Name'];
$Password = $_POST['Password'];
$returnArr['Name']=$Name;
$returnArr['Password']=$Password;
header('Content-type:text/json');
echo json_encode($returnArr,JSON_UNESCAPED_UNICODE);
?>
返回结果:
用户名:ASD
密码:123
最开始的时候,大家都习惯使用这样的编码来实现异步编程,但这样原生的编码方式不方便,如果有嵌套那么代码也显得冗长,不方便阅读,现在几乎没有人再使用它。
Jquery的出现让编程方式做了很大的改变。
3、JQuery的AXAJ方法(函数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="jquery-3.4.1.min.js" charset="utf-8"></script>
<title>Jquery</title>
</head>
<body>
<script>
$.ajax({
url:'http://127.0.0.1/ES6_Base/ASD.php',
data:{
"Name":"ASD",
"Password":"123"
},
type:'POST',
async:true,
success:function (JsonData) {
console.log("用户名:"+JsonData['Name']);
console.log("密码:"+JsonData['Password']);
}
});
</script>
</body>
</html>
返回和上面一样的结果。
JQuery也是封装了原生AXAJ的API,使用起来方便快捷。
在很多框架里可以看到JQuery的身影,它们都集成了JQuery,比如LayUI、EasyUI等。
JQuery自2006年诞生起在很长一段时间里相当流行,是当时使用最为广泛和频繁的函数库,但目前逐渐在淡出。主要原因可能是回调地狱、ECMAScript6下有更好的异步编程模式等等。
4、Promise对象
Promise是ECMAScript6中提供的用于解决异步编程的类。
使用它有助于书写优雅、复杂的异步任务,改善了异步编程的困难,避免了回调地狱,比传统的解决方案回调函数和事件更合理和更强大。
通俗地理解,就是使用同步编程的写法可以解决异步编程的问题。
const p=new Promise( (resolve,reject)=> {
//执行任务
//任务成功时执行resolve,可以包含结果
//任务失败时执行reject,可以包含错误提示信息
}).then( ( value )=>{
//获取resolve的结果再进一步进行处理
}).catch( ( reason )=>{
//获取reject的信息并进一步处理
})
上面是我们经常使用的写法,也可以使用下面的写法,效果与上面一样。
const p=new Promise( (resolve,reject)=> {
//执行任务
//任务成功时执行resolve,可以包含结果
//任务失败时执行reject,可以包含错误提示信息
}).then( ( value )=>{
//获取resolve的结果再进一步进行处理
} ,( reason )=>{
//获取reject的信息并进一步处理
})
注意点:
(1) promise对象有三种状态,分别是pending(准备中)、fulfilled(成功/完成)、rejected(拒绝/失败)。
(2) promise对象的状态改变是一次性的,也就是只能改变一次,要么pending -> fulfilled,要么pending -> rejected。
(3) 通过执行resolve改变promise对象状态由pending -> fulfilled,执行reject改变promise对象状态由pending -> rejected。
(4) then方法返回的是promise对象,promise支持方法调用的链式写法。
(5) 当promise的状态为rejected或者执行体中的代码异常时执行catch函数。
虽然promise相比Jquery的Axaj有很大的改观,的确也解决了异步编程中常遇到的回调地狱、回调函数的嵌套问题,但实际写代码过程中,依然觉得promise如果then很多的情况下阅读代码不是很方便。
promise在现在的异步编程中应用相当普遍。
5、asyc/await
比较而言,ECMAScript7(2016年)中应用于异步编程的asyc/await则人性化了许多,真正实现了异步处理同步化(写法)。
async GetListTask(id){
let result;
result=await this.GetListTask1(id) //等待获取任务列表1
//......处理
result=await this.GetListTask2(id) //等待获取任务列表2
//......处理
}
注意点:
(1) 如果函数中包含了await但函数前面没有冠以async则程序会报错。
(2) 函数前面直接使用asyc但函数体内无await程序并不会报错,但无意义,asyc/await必须成对出现才有意义。
现在很多设计异步编程的的开发都使用asyc/await。
6、Generator(生成器)
通过生成器返回的迭代器对象,根据需要执行next()方法来控制程序进度。
function* ToDo() {
console.log("执行第一步任务");
yield 111;
console.log("执行第二步任务");
yield 222;
console.log("执行第三步任务");
}
const myToDo = ToDo(); //获取生成器对象
console.log(myToDo.next().value); // 输出:111,到yield 111为止
console.log(myToDo.next().value); // 输出:222,到yield 222为止
console.log(myToDo.next().value); // 输出:undefined,任务执行完毕
输出结果:
执行第一步任务
111
执行第二步任务
222
执行第三步任务
undefined
通过迭代来控制:
for(let item of myToDo) {
console.log( item )
}
结果输出:
执行第一步任务
111
执行第二步任务
222
执行第三步任务
这种方式有特定的应用场景,感觉还是习惯asyc/await。
7、Axios
Axios是一个基于Promise、用于浏览器和Node.js的HTTP客户端,它也是对原生XMLHTTPRequest对象的promise封装。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Axios</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
axios.post('http://127.0.0.1:8018/JS/ECMAScript6/ES6_Base/ASD.php',"Name=ASD&Password=123")
.then(function(response){
console.log('得到结果')
console.log(response.data);
})
.catch(function(error){
console.log('错误提示')
console.log(error);
})
</script>
</body>
</html>
结果输出:
得到结果
{Name: "ASD", Password: "123"}
前端框架中使用Vue的多使用axios来执行异步请求任务。
8、fetch对象
fetch被称为下一代的Ajax技术,采用promise方式来处理数据,代码结构比较简洁,fetch不是对XMLHTTPRequest对象的进一步的封装,是新的异步编程实现方法和规范。
fetch默认不会带有cookie,需要添加配置项,fetch不能再请求过程中检测进度。
fetch('http://127.0.0.1:8018/JS/ECMAScript6/ES6_Base/ASD.php',{method:'post',body:'Name=ASD&Password=123',headers:{ 'Content-Type':'application/x-www-form-urlencoded' } }).then(data=>{
//text()是fetch的一部分,它返回的是promise对象,用于获取后台返回的数据
return data.text();
}).then(result=>{
//这里获得最终的数据
console.log(result);
})
结果输出:
{"Name":"ASD","Password":"123"}