浅谈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、扩展运算符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值