龙空技术网

JavaScript语言基础:Promise是如何解决回调地狱问题的?

代码开发 232

前言:

今天各位老铁们对“promisereject终止promise”大约比较看重,同学们都想要了解一些“promisereject终止promise”的相关文章。那么小编在网上网罗了一些对于“promisereject终止promise””的相关资讯,希望朋友们能喜欢,看官们一起来学习一下吧!

链接:

众所周知的,Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行。本特性带来的问题就是,一些将来的、未知的操作,必须异步实现。本文将讨论一个比较常见的异步解决方案——Promise。

Promise解决的问题

相信每个前端都遇到过这样一个问题,当一个异步任务的执行需要依赖另一个异步任务的结果时,一般会将两个异步任务嵌套起来,这种情况发生一两次还可以,但是发生很多次之后,代码就会变成这个熊样:

	async1(function(){		async2(function(){			async3(function(				async4(funciton(){					async5(function(){											 // 直到地老天荒					});				});			));			});	});

这就是所谓的回调地狱,代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护。

Promise的基本用法

时至今日,很多现代浏览器都已经实现,但是为了兼容,建议自行对Promise进行封装或者使用第三方的解决方案(如webpack对es6语法进行编译)。得到一个Promise构造函数,新建一个Promise的实例:

	var _promise = new Promise(function(resolve, reject){		setTimeout(function(){			var rand = Math.random();			if(rand<0.5){				resolve("resolve" + rand);			}else{				reject("reject" + rand);			}		},1000);			});	

由上所示,Promise的构造函数接收一个函数作为参数,该函数接受两个额外的函数,resolve和reject,这两个函数分别代表将当前Promise置为fulfilled(解决)和rejected(拒绝)两个状态。Promise正是通过这两个状态来控制异步操作的结果。接下来我们将讨论Promise的用法,实际上Promise上的实例 _promise是一个对象,不是一个函数。在声明的时候,Promise传递的参数函数会立即执行,因此Promise使用的正确姿势是在其外层再包裹一层函数。

	var run = function(){		var _promise = new Promise(function(resolve, reject){			setTimeout(function(){				var rand = Math.random();				if(rand<0.5){					resolve("resolve" + rand);				}else{					reject("reject" + rand);				}			},1000);		});		return _promise;	}	run();

这是Promise的正常用法,接下来,就是对异步操作结果的处理,接着上面创建的函数run()

	run().then(function(data){		console.log(data);	});

每个Promise的实例对象,都有一个then的方法,这个方法就是用来处理之前各种异步逻辑的结果。

那么, 这么做有什么用?

当然有用,到目前为止,我们学会了Promise的基本流程,但是这种用法和嵌套回调函数似乎没什么区别,而且增加了复杂度。但是我们说了,Promise的用处,实际上是在于多重异步操作相互依赖的情况下,对于逻辑流程的控制。Promise正是通过对两种状态的控制,以此来解决流程的控制。请看如下代码:

run().then(function(data){		//处理resolve的代码		cosnole.log("Promise被置为resolve",data);	},function(data){		//处理reject的代码		cosnole.log("程序被置为了reject",data);	})

如果异步操作获得了我们想要的结果,那我们将调用resolve函数,在then的第一个作为参数的匿名函数中可以获取数据,如果我们得到了错误的结果,调用reject函数,在then函数的第二个作为参数的匿名函数中获取错误处理数据。 这样,一个次完整的Promise调用就结束了。对于Promise的then()方法,then总是会返回一个Promise实例,因此你可以一直调用then,形如run().then().then().then().then().then()..... 在一个then()方法调用异步处理成功的状态时,你既可以return一个确定的“值”,也可以再次返回一个Promise实例,当返回的是一个确切的值的时候,then会将这个确切的值传入一个默认的Promise实例,并且这个Promise实例会立即置为fulfilled状态,以供接下来的then方法里使用。如下所示:

	run().then(function(data){		console.log("第一次",data);		return data;	}).then(function(data){		console.log("第二次",data);		return data;	}).then(function(data){		console.log("第三次",data);		return data;	});	/* 异步处理成功的打印结果:		第一次 resolve0.49040459200760167d.js:18 		第二次 resolve0.49040459200760167d.js:21 		第三次 resolve0.49040459200760167		由此可知then方法可以无限调用下去。	*/

根据这个特性,我们就可以将相互依赖的多个异步逻辑,进行比较顺序的管理了。下面举一个拥有3个异步操作的例子,代码有些长。

这样,连续依赖的几个异步操作,就完成了,解决了让人头痛的回调地狱问题。

异步操作拒绝及终止调用链

前文提到过,then方法可以接收两个匿名函数作为参数,第一个参数是Promise置为fulfilled状态后的回调,第二个是置为rejected状态的回调。在很多情况下,如果连续的几个异步任务,其中某个异步任务处理失败,那么接下来的几个任务很大程度上就不需要继续处理了,那么我们该如何终止then的调用链呢?在Promsie的实例上,除了then方法外,还有一个catch方法,catch方法的具体作用,我们沿用上面的代码,将run_a()改造一下来看:

以上代码简单描述了如何终止链式调用,值得注意的是,catch方法还有try catch的作用,也就是说,then里面的逻辑代码如果出现了错误,并不会在控制台抛出,而是会直接有catch捕获。

标签: #promisereject终止promise