ES6中的Promis的使用方法

什么是Promise?

Promise是由 CommonJS 在 Promises/A 规范中提出来的,是js一部编程的重要概念,是比较就行的javascript一部变成解决方案之一。

常见的异步编程解决方案

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象

在这里以上的及以上的集中解决方案就不一一说了,我们就拿一部函数简单说一下吧

1.在JQuery中我们通过异步请求拿到后台数据,都是以回调的方式。

$.get(url, (res => {
    console.log(res);
})

2.如果我们需要发送多个请求,并且这些请求是有执行顺序的;那么我们就只能嵌套使用;如果有很多个嵌套呢?这就形成了“嵌套地狱”·

$.get(url1, res1 => {
	console.log(res1);
	$.get(url2, res2 => {
		console.log(res2);
		$.get(url3, res3 => {
			console.log(res3);
			......
		})
	})
})

这样一来,在处理越多的异步逻辑时,就需要越深的回调嵌套;这个问题我们一会来解决


promises相关概念

1. then()方法介绍

根据 Promise/A 规范,promise是一个对象,只需要then这一个方法。then方法带有如下三个参数:

  • 成功回调
  • 失败回调
  • 前进回调(规范没有要求包括前进回调的实现)。

一个全新的 promise 对象从每个 then 的调用中返回。

2. Promise对象状态

Promise 对象代表一个异步操作,其不受外界影响,有三种状态:

  • Pending:进行中、未完成的
  • Resolved:已完成,又称 Fulfilled
  • Rejected:已失败

1、创建出来的Promise从未完成的状态开始,如果调用成功将进入已完成状态,如果失败将进入已失败状态。
2、当一个Promise移动到已完成状态,那么所有注册到它的成功回调将被调用,而且会将成功结果传给它;另外,任何注册到promise的成功回调,将会在它已经完成以后立即被调用。
3、当一个Promise移动到已失败状态,那么调用的是失败调用;另外之后注册到Promise的回调将不会被调用。
4、对包含前进特性的实现来说,Promise在它离开未完成状态以前的任何时刻,都可以更新它的 progress。当progress被更新,所有的前进回调(progress callbacks)会被传递以progress的值,并被立即调用。前进回调被以不同于成功和失败回调的方式处理;如果你在一个 progress 更新已经发生以后注册了一个前进回调,新的前进回调只会在它被注册以后被已更新的 progress 调用。
5、注意:只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

Promises的优势

1. 解决回调地狱问题

在我们上面说到的那个agax请求的```回调地狱``问题;代码如下:

$.get(url1, res1 => {
	console.log(res1);
	$.get(url2, res2 => {
		console.log(res2);
		$.get(url3, res3 => {
			console.log(res3);
			......
		})
	})
})

我们使用Promis解决的话,代码就会提高可读性;如下:

request(url) {
	return new Promise((resolve, reject) => {
		$.get(url, res => {
			resolve(res);
		})
	});
}

request(url1).then(data => {
	return request(url2);
}).then(data => {
	return request(url3);
});
2. 更好的处理异常

比如下面代码我们使用 setTimeout 模拟异步操作,在其中抛出了个异常。但由于异步回调中,回调函数的执行栈与原函数分离开,导致外部无法抓住异常。

function testError(e) {
    setTimeout(() => {
        throw Error('请求失败')
    }, 2000)
}
 
try {
    testError(() => {
        console.log('请求处理');		// 永远不会执行
    })
} catch (error) {
    console.log('触发异常', error);	// 永远不会执行
}

使用Promises,通过reject方法把Promise````的状态置为rejected,这样我们在then```中就能捕捉到,然后执行Error情况的回调

function testError(callback) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             reject('请求失败');
        }, 2000)
    })
}

testError().then(function(data){
	console.log('请求处理');
    console.log(data);
},function(reason, data){
	console.log('触发异常');
    console.log(reason);
});

当然我们在catch方法中处理reject回调;如下:

testError().then(data => {
	console.log('请求处理');
	console.log(data);
}).catch(reason => {
	console.log('触发异常');
	console.log(reason);
});

Promises方法详解

1. then()方法

简单来说,then()方法就是把原来的方法分离出来,在异步执方法调用完成以后,然后链式的用方法执行回调函数。
Promise的优势就在于这个链式调用。我们可以在then()方法中继续返回Promise对象,然后继续调用后面的then()方法。

而 Promise 的优势就在于这个链式调用。我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。

让我们来开一下实例,这里我们使用setTimeout来模仿异步操作:

function f1() {
	console.log("第一个方法开始执行!!!");
	return new Promise(function(resolve, reject){// 第一个异步操作
		setTimeout(function() {
			console.log("第一个回调执行完成!!!");
			resolve("data1");
		}, 1000);
	});
}

function f2(data) {
	console.log(`第二个方法开始执行:方法一的执行结果为***${data}***!!!`);
	return new Promise(function(resolve, reject){// 第二个异步操作
		setTimeout(function() {
			console.log("第二个个回调执行完成!!!");
			resolve("data2");
		}, 1000);
	});
}

function f3(data) {
	console.log(`第三个方法开始执行:方法二的执行结果为***${data}***!!!`);
	return new Promise(function(resolve, reject){// 第三个异步操作
		setTimeout(function() {
			console.log("第三个个回调执行完成!!!");
			resolve("data3");
		}, 1000);
	});
}
f1().then(data => {
	return f2(data);
}).then(data => {
	return f3(data);
}).then(data => {
	console.log(data);
});

当然我们的代码可以更简单,如下:

f1().then(f2).then(f3).then(data => {
	console.log(data);
});

执行结果如下:

第一个方法开始执行!!!
第一个回调执行完成!!!
第二个方法开始执行:方法一的执行结果为***data1***!!!
第二个个回调执行完成!!!
第三个方法开始执行:方法二的执行结果为***data2***!!!
第三个个回调执行完成!!!
data3
2. reject()方法

上面样例我们通过resolve方法把Promise的状态置为完成态Resolved,这时then方法就能捕捉到变化,并执行“成功”情况的回调。
reject方法就是把Promise的状态置为已失败Rejected,这时then方法执行“失败”情况的回调。

我们修改一下上面的例子,在线执行一次:

function f1() {
	console.log("第一个方法开始执行!!!");
	return new Promise(function(resolve, reject){// 第一个异步操作
		setTimeout(function() {
			console.log("第一个回调执行完成!!!");
			reject("调用失败");
		}, 1000);
	});
}

function f2(data) {
	console.log(`第二个方法开始执行:方法一的执行结果为***${data}***!!!`);
	return new Promise(function(resolve, reject){// 第二个异步操作
		setTimeout(function() {
			console.log("第二个个回调执行完成!!!");
			resolve("data2");
		}, 1000);
	});
}

f1().then(f2, data => {
	console.log(data);
});

执行结果如下:

第一个方法开始执行!!!
第一个回调执行完成!!!
调用失败

如果你决定只处理异常,那不妨把then()的第一个参数设置为null

3. catch()方法

其实它和then()的第二个方法类似,用来指定reject()的回调,但是它还有另外一个用处,如下演示:

function f1() {
	console.log("第一个方法开始执行!!!");
	return new Promise(function(resolve, reject){// 第一个异步操作
		setTimeout(function() {
			console.log("第一个回调执行完成!!!");
			reject("调用失败");
		}, 1000);
	});
}

function f2(data) {
	console.log(`第二个方法开始执行:方法一的执行结果为***${data}***!!!`);
	return new Promise(function(resolve, reject){// 第二个异步操作
		setTimeout(function() {
			console.log("第二个个回调执行完成!!!");
			resolve("data2");
		}, 1000);
	});
}

f1().then(data => {
	f2(data);
}).catch(err => {
	console.log(err);
});

上面的例子,f2()方法并没有执行;这也就是catch()的另一个用处,在链式调用then()方法的时候,如果中间有一个出错了,那么他不会卡死,而是忽略后面的then()方法,直接调用catch()方法进行异常处理。

我们还可以添加多个catch(),进行精确的步骤操作:

test().then(function() {
 return a();
}).catch(TypeError, function(e) {
// 如果定义了a,将在此处结束,因为
}).catch(ReferenceError, function(e) {
// 如果完全没有定义a,将在此处结束
}).catch(function(e) {
// 如果上面都没有捕捉到错误,将在这里捕捉
});
4. all()方法

Promiseall()方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

例如:

function f1() {
	console.log("第一个方法开始执行!!!");
	return new Promise(function(resolve, reject){// 第一个异步操作
		setTimeout(function() {
			console.log("第一个回调执行完成!!!");
			resolve("data1");
		}, 1000);
	});
}

function f2() {
	console.log(`第二个方法开始执行!!!`);
	return new Promise(function(resolve, reject){// 第二个异步操作
		setTimeout(function() {
			console.log("第二个个回调执行完成!!!");
			resolve("data2");
		}, 1000);
	});
}
Promise.all([f1(), f2()]).then(data => {
	console.log(data);
});

执行结果:

第一个方法开始执行!!!
第二个方法开始执行!!!
第一个回调执行完成!!!
第二个个回调执行完成!!!
> ["data1", "data2"]
5. race()方法

race按字面解释,就是赛跑的意思。race()的用法与all()一样,只不过all()是等所有异步操作都执行完毕后才执行then()回调。而race()的话只要有一个异步操作执行完毕,就立刻执行then()回调。

function f1() {
	console.log("第一个方法开始执行!!!");
	return new Promise(function(resolve, reject){// 第一个异步操作
		setTimeout(function() {
			console.log("第一个回调执行完成!!!");
			resolve("data1");
		}, 1000);
	});
}

function f2() {
	console.log(`第二个方法开始执行!!!`);
	return new Promise(function(resolve, reject){// 第二个异步操作
		setTimeout(function() {
			console.log("第二个个回调执行完成!!!");
			resolve("data2");
		}, 1000);
	});
}
Promise.race([f1(), f2()]).then(data => {
	console.log(data);
});

执行结果:

第一个方法开始执行!!!
第二个方法开始执行!!!
第一个回调执行完成!!!
data1
第二个个回调执行完成!!!

注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。

参考:
https://www.cnblogs.com/sweeeper/p/8442613.html
http://www.hangge.com/blog/cache/detail_1639.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值