ES6引入了Promise对象解决异步问题

什么是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();
})();



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ES6(ECMAScript 2015)引入Promise对象,它是一种异步编程的解决方案。当一个异步操作成后,Promise对象会返回一个代表操作结果的值,而不是像传统方式那样使用回调函数。 Promise对象的then方法用于指定操作成功和失败时的回调函数。而且可以将then方法连续使用,形成链式调用。当一个Promise对象的then方法返回另一个Promise对象时,后续的then方法都会等待Promise对象的状态改变。 链式调用的好处在于减少了回调函数嵌套的层数,提高了代码的可读性和可维护性。通过then方法的链式调用,可以构建一串异步操作,使得代码逻辑更加清晰。 例如: ``` function getJSON(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error('Unable to fetch data')); } } }; xhr.send(); }); } getJSON('/data/user.json') .then(user => { return getJSON(`/data/profile/${user.id}.json`); }) .then(profile => { console.log(profile); }) .catch(error => { console.error(error); }); ``` 上述代码展示了一个获取用户信息和个人资料的异步操作,其中getJSON函数返回一个Promise对象。通过then方法的链式调用,可以先获取用户信息,然后再获取个人资料。如果有任何一个异步操作失败,则会进入catch回调函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值