什么是Promise
Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作。
- 优点
(1) promise对象,进行链式回调,可以将 异步操作 以 同步操作的流程 表达出来,避免层层嵌套,避免"厄运回调金字塔"。
(2) 可以有多个then()连缀书写。
(3) 不仅给出了异步操作成功的代码解决方案,还给出了异步操作失败和完成的解决方案。
new Promise(function(resolve,reject){
//异步操作
}).then(function(){
//异步操作成功
}).catch(function(){
//异步操作失败
}).finally(function(){
//异步操作完成
})
- 缺点
(1) promise一旦新建,就会立即执行,无法取消
(2) 如果不设置回掉函数,promise内部抛出的错误就不会反应到外部
(3) 处于pending状态时,是不能知道目前进展到哪个阶段的 ( 刚开始?,即将结束?)
同步与异步
JavaScript的执行机制是「单线程」。
所谓的单线程,是指JS引擎中负责解释和执行JavaScript的代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完了之后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。
但实际上还有其他线程,如事件触发线程、ajax请求线程等。
这也就引发了同步和异步的问题。
同步
同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致「线程阻塞」。
var x = true;
while(x);
console.log("don't carry out"); //不会执行
这个例子就是同步模式,其中while是一个死循环,将会堵塞进程,所以第三句一直不会执行。
同步模式比较简单,也较容易编写。但问题也显而易见,如果请求的时间较长,而阻塞了后面代码的执行,体验是很不好的。因此对于一些耗时的操作,异步模式则是更好的选择。
异步
异步模式,即与同步模式相反,可以一起执行多个任务,函数调用后不会立即执行返回的结果。
setTimeout(function() {
console.log('taskA, asynchronous');
}, 0);
console.log('taskB, synchronize');
//while(true);
我们可以看到,计时器的时间为0,但是taskB还是比taskA先执行,这是因为定时器是异步的,异步问题会在当前脚本的所有同步任务执行完才会执行。
如果将上例注释去掉,这个异步(定时器)是不会执行的,成为了死循环,堵塞了同步任务进程。
Promise
//构建Promise
let promise = new Promise(function (resolve, reject) {
if (/* 异步操作成功 */) {
resolve(data);
} else {
/* 异步操作失败 */
reject(error);
}
});
promise.then(function(){
//书写调用了resolve()时执行的代码
},function(){
//书写调用了reject()时执行的代码
})
类似构建对象,我们使用new来构建一个Promise。Promise接受一个「函数」作为参数,该函数的两个参数分别是resolve和reject。这两个函数就是就是「回调函数」,由JavaScript引擎提供。
resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成后,可以使用then方法指定resolve状态和reject状态的回调函数。
例 : 封 装 一 个 弹 框 ( c o n f i r m ( ) ) 例:封装一个弹框(confirm()) 例:封装一个弹框(confirm())
function $confirm(message){
return new Promise((resolve,reject)=>{
let temp=window.confirm(message);
if(temp){
resolve()
}else{
reject()
}
})
}
$confirm("您确定关闭吗?").then(()=>{
console.log('关闭了')
}).catch(()=>{
console.log('取消了')
})
例 : 加 载 一 个 图 片 例:加载一个图片 例:加载一个图片
function loadImage(parent,url){
return new Promise((resolve,reject)=>{
var img=new Image();
img.src=url;
parent.appendChild(img);
img.onload=function(){
resolve(this);
}
img.onerror=function(){
reject();
}
})
}
loadImage(box,'images/03.jpg').then(function(obj){
console.log("图片加载成功");
console.log(obj.width);
}).catch(function(){
console.log("图片加载失败");
})
加载图片成功后获得图片的宽。还有打印“加载成功”提示文本。
obj指的就是resolve(this)中的this。指图片。(this指向)
例
:
加
载
多
个
图
片
例:加载多个图片
例:加载多个图片
当所有图片都加载成功后,输出“所有图片加载成功”;有任意图片没有加载成功,输
出“有图片没有加载成功”。
静态方法:Promise.all(array)
功能:返回一个Promise实例,参数array是一个元素为Promise实例的数组。当数组中所有的Promise实例均执行resolve()方法后,整个Promise实例才会表示成功。
function loadImage(parent,url){
return new Promise((resolve,reject)=>{
var img=new Image();
img.src=url;
parent.appendChild(img);
img.onload=function(){
resolve(this);
}
img.onerror=function(){
reject();
}
})
}
let imgs=['1.jpg','2.jpg','3.jpg','4.jpg'];
let pro=[];
for (var i = imgs.length - 1; i >= 0; i--) {
let temp = loadImage(box,'images/0' + imgs[i]);
pro.push(temp);
}
Promise.all(pro).then(()=>{
console.log("所有图片都加载成功了")
}).catch(()=>{
console.log("有图片没有加载成功")
})
例 : 加 载 一 张 图 片 , 在 图 片 加 载 成 功 后 输 出 图 片 的 宽 度 和 高 度 , 若 图 片 加 载 失 败 则 显 示 例:加载一张图片,在图片加载成功后输出图片的宽度和高度,若图片加载失败则显示 例:加载一张图片,在图片加载成功后输出图片的宽度和高度,若图片加载失败则显示
let promise=new Promise(function(resolve,reject){
var img=new Image();
img.src="images/02.jpg";
box.appendChild(img);
img.onload=function(){
resolve(this);
}
img.onerror=function(){
reject();
}
})
promise.then(function(obj){
console.log(`图片宽度=${obj.width}`);
console.log(`图片高度=${obj.height}`);
},function(){
console.log("图片加载失败");
})
封
装
A
j
a
x
技
术
封装Ajax技术
封装Ajax技术
(1)原生JavaScript:XMLHttpRequest()
(2)jQuery:$.ajax()
(3)Vue.js:axios
(4)小程序:wx.request()
如何利用Axios技术提交一个Ajax请求:
- $axios.get(url,{}).then().catch();
- $axios.post(url,{}).then().catch();
问题:因为 $axios后面还要跟具体的不同而两个方法(get()、post()),所以不能使
用function进行封装。
解决:使用类封装(混合模式:属性定义在构造函数中,方法定义在原型下)。
/*创建一个构造函数*/
function Axios(){}
/*创建Ajax类的方法*/
Axios.prototype.get=function(){}
Axios.prototype.post=function(){}
/*创建Ajax类的实例*/
let $axios=new Axios();
$axios.get(); /*发送get请求*/
$axios.post(); /*发送post请求*/
封装AJAX技术
/*先创建构造函数*/
function Axios(){
this.xhr = new XMLHttpRequest();
}
/*创建Axios类的方法*/
Axios.prototype.toString=function(data){
let temp=[];
for (let i in data) {
temp.push(`${i}=${data[i]}`) 'name=1','age=10']
}
return temp.join('&')
}
Axios.prototype.get=function(url,data){
return new Promise((resolve,reject)=>{
data=data.constructor===Object?this.toString(data):data;
this.xhr.open('get',url+'?'+data);
this.xhr.send(null);
this.onreadystatechange=function(){
if(this.readyState===4){
if(this.status===200){
resolve(this.responseText.trim())
}
}
}
})
}
Axios.prototype.post=function(url,data){
return new Promise((resolve,reject)=>{
data=data.constructor===Object?this.toString(data):data;
this.xhr.open('post',url);
this.xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
this.xhr.send(data);
this.onreadystatechange=function(){
if(this.readyState===4){
if(this.status===200){
resolve(this.responseText.trim())
}
}
}
})
}
/*创建Axios类的实例*/
let $axios=new Axios();
/*调用Axios类的方法*/
btn.onclick=function(event){
event.preventDefault();
let url='checkGradeG.jsp';
let data={
exno:'10010',
exname:'张三'
};
$axios.post(url,data).then((res)=>{
console.log(JSON.parse(res))
})
}
也可以将封装的内容和对封装的使用进行分离
例如单独写一个js文件axios.js,用的时候直接引入就行了。
(function(){
//函数自执行
//先创建构造函数
function Axios(){
this.xhr = new XMLHttpRequest();
}
//创建Axios类的方法
Axios.prototype.toString = function(data){
let temp = [];
for(let i in data){
temp.push(`${i}=${data[i]}`);
}
return temp.join('&');
}
Axios.prototype.get = function(url,data){
return new Promise((resolve,reject)=>{
data=data.constructor===Object?this.toString(data):data;
this.xhr.open('get',url + '?' + data);
this.xhr.send(null);
this.xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
resolve(this.responseText.trim());
}
}
}
})
}
Axios.prototype.post = function(url,data){
return new Promise((resolve,reject)=>{
data=data.constructor===Object?this.toString(data):data;
this.xhr.open('post',url);
this.xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
this.xhr.send(data);
this.xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
resolve(this.responseText.trim());
}
}
}
})
}
//创建Axios类的实例
//window暴露变量
window.$axios = new Axios();
})();