浅谈ES6--Promise

最近准备系统深入的学习一下promise这个东西,将从它的概念,使用场景,优势等方面做一个系统的总结。

先总结下每次遇到的关于promise的几种题型,比如判断promise打印顺序,实现合并发送两个请求,发送多个请求,且有依赖关系,如何用promise更好的实现,是否可以封装成队列?


场景一、实现每隔1s打印一个参数

function runAsync1 () {
	var p1 = new Promise((resolve, reject) => {
		return setTimeout(() => {
			console.log(1);
			resolve('成功1');
		}, 1000);
	});
	return p1;
}

function runAsync2 () {
	var p2 = new Promise((resolve, reject) => {
		return setTimeout(() => {
			console.log(2);
			resolve('成功2');
		}, 2000);
	})
	return p2;
}

function runAsync3 () {
	var p3 = new Promise((resolve, reject) => {
		setTimeout(() => {
			console.log(3);
			resolve('成功3');
		}, 3000);
	})
	return p3;
}

runAsync1().then(value => {
   console.log(value);
   return runAsync2();
}).then(value => {
	console.log(value);
	return runAsync3();
}).then(value => {
	console.log(value);
});

上面的代码实现了每隔1s执行一次回调函数,promise接受一个函数作为参数,函数里接受两个参数:resolve, reject。
这两个参数也是函数,用于分别处理异步操作成功或失败的结果。promise对象还有then/catch等方法,then方法对应处理promise对象中resolve弹出的数据。catch方法对应处理promise对象中reject弹出的数据。
我们看到上面的例子中,每个setTimeout还执行了resolve的函数,这里如果不执行resolve函数会发现,promise无法将链式的操作进行下去。这是为什么呢?这就要说说resolve,和reject都做了什么。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

看了官方解释,我们就知道了resolve会将异步操作的结果作为参数传递出去,通过promise的then方法接收。没有resolve,代码就不会执行到then方法里去。

了解了resolve的意义,再回到上面的需求场景中,就明白了没有resolve,这个promise对象就没有从pending变成resolved,自然就不会走到后面的then方法咯。再说回需求,每隔1s打印一个参数,我们可以用setTimeout来实现间隔1s打印参数的操作,并将它包装成一个promise对象。由于promise在构建之后会立即执行,所以一般被包在函数里。通常在考察eventloop中,也经常用promise的这一特性混淆视听,所以需要注意这个特点哦!

关于promise,setTimeout打印顺序的问题:

console.log(1);
setTimeout(() => {
	console.log(2);
}, 0);
new Promise((resolve, reject) => {
	console.log(3);
	setTimeout(() => {
		console.log(4);
		resolve();
	}, 0);
	console.log(5);
});
console.log(6);
// 1,3,5,6,undefined,2,4

场景二、实现并发两个请求

async function getData1(u1) {
	let data = await fetch(u1);
	return data;
}
async function getData1(u2) {
	let data = await fetch(u1);
	return data;
}
promise.All([getData1(), getData2()]).then(dataArr => {
	console.log(dataArr);//dataArr是一个数组,dataArr[0]是getData1()的数据,dataArr[1]是getData2()的数据。
}).catch(err => {
	console.log(err);
});

上面的代码不太想的清resolve是什么含义,简单说下自己的理解吧,首先复习一下setTimeout的语法。

回顾setTimeout使用方法:

在这里插入图片描述
setTimeout eg1:

function test(ms) {
	var p = new Promise((resolve, reject) => {
	  	setTimeout(resolve, ms, 'done');
	});
	return p;
}
test(100).then(value => {
	alert(value);
});

setTimeout eg2:

var code = function (arr) {
	console.log(arr.reduce((a, b) => (a + b)); 
}
setTimeout(code, 1000, [1,2,3]); //6;1000ms后将数组[1,2,3]传入code函数并执行code回调函数。

setTimeout接收一个代码串,code/function,第二个参数是milliseconds,调用code需要等待的时间,既milliseconds时间后,调用执行code代码串,或调用function,第三个参数是传入执行函数的参数。
如此就可以解释上面的代码啦,经过ms毫秒后,调用resolve函数,并将’done’传入给resolve函数。


场景三、用promise封装一个ajax

function getJson(url) {
	var promise = new Promise((resolve, reject) => {
		const client = new XMLHttpRequest();
		client.open('GET', url); //用get方式请求url;
		client.onreadychangestate = function () {
			if (~~this.readyState !== 4) {
				return;
			}
			if (~this.status === 200) {
				resolve(this.response);
			} else {
				reject(new Error('出错啦'));
			}
		}
		client.send();//发送
	});
}
getJson('hyt/data/image').then(json => {
	console.log(json);
}, err => {
	console.log('出错啦'+ err);
})

简单说下封装原理,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。
将ajax这样的异步操作包装成promise对象,写在getJson函数里调用,当ajax异步操作完成后,或执行resolve回调函数,并弹出response,跳到then方法里。或执行reject回调函数,并弹出所带参数,跳到then方法里,执行相应操作,(咦?这里有个问题,then方法接收两个函数参数,它们分别有什么意义呢?)至此,简单的ajax封装就完成啦。

关于刚才的疑问,可以在官网中找到答案:
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

这里想说一下XMLHttpRequest对象包含很多属性方法,这些属性方法帮助我们实现发送一个http请求,得到response或请求失败的信息,从而完成请求的过程。需要花时间梳理一下http请求的过程,几个状态码的含义。才能封装出一个完整的http请求哦!(我实在是不想梳理!不想背哇!)。

在这里插入图片描述


场景四、一个异步操作的结果是返回另一个异步操作

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))

promise还有其他的api:all、race、try、catch、finally…鉴于时间有限,就先不一一展开啦!

当然找时间还要研究一下ES6其他的几个重要概念。
1、weakmap
2、generator
3、async await
4、class
5、扩展运算符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值