ES6 Promise

3 篇文章 0 订阅

1、Promise介绍

Promise 是异步编程的一种解决方案,接下来我会用延迟函数来模拟网络请求(异步操作)。

Promise是个对象,我们用他的时候是要new的,在new这个Promise的时候是要求传入参数的:

new Promise(参数)

而这个参数本身又是一个函数。也就是说,这个Promise在new的时候就要求我们给它传入一个函数作为参数,也就是:

new Promise(() => {})

但是我们给这个Promise传入的这个函数本身它也包含两个参数,一个叫resolve,一个叫reject,也就是:

new Promise((resolve, reject) => {})

而这里的两个参数 resolve 和 reject 本身又是函数。

以前我们处理异步请求:

// 用setTimeout模拟网络请求
setTimeout(() => {
	console.log('Hello World');
	// 我们以前会在网络请求回来以后在这里进行一些操作,比如数据处理等等
	
	// 假如在这里我们又要进行异步操作,那么:
	setTimeout(() => {
		...
		// 假如在这里我们又要进行异步操作,那么就会出现回调地狱的情况
	}, 1000)

}, 1000)

现在用 Promise进行封装:

new Promise((resolve, reject) => {
	// 用setTimeout模拟网络请求
	setTimeout(() => {
		// 我们在这里调用resolve方法
		resolve()
	}, 1000)
})

我们上面调用了resolve方法,那么它会自动的调用new Promise().then() 方法,也就是:

new Promise((resolve, reject) => {
	// 用setTimeout模拟网络请求
	setTimeout(() => {
		// 我们在这里调用resolve方法
		resolve()
	}, 1000)
}).then()

而这个then方法接受的参数又是一个函数,也就是:

new Promise((resolve, reject) => {
	// 用setTimeout模拟网络请求
	setTimeout(() => {
		// 我们在这里调用resolve方法
		resolve()
	}, 1000)
}).then(() => {})

那么我们可以把数据处理等操作放到这个then的方法里面去做:

new Promise((resolve, reject) => {
	// 用setTimeout模拟网络请求
	// 第一次网络请求
	setTimeout(() => {
		// 我们在这里调用resolve方法
		resolve()
	}, 1000)
	
}).then(() => {
	// 处理第一次网络请求的结果
	console.log('Hello World');
	
	// 第二次网络请求
	setTimeout(() => {
		...
	}, 1000)
})

但是上面还是有嵌套异步请求(第一次网络请求的结果和第二次网络请求放在一块了),我们可以再进行这样写:

new Promise((resolve, reject) => {
	// 用setTimeout模拟网络请求
	// 第一次网络请求
	setTimeout(() => {
		resolve()
	}, 1000)
	
}).then(() => {
	// 处理第一次网络请求的结果
	console.log('Hello World');
	
	return new Primise((resolve, reject) => {
		// 第二次网络请求
		setTimeout(() => {
			resolve()
		}, 1000)
	})
}).then(() => {
	// 处理第二次网络请求的结果
})

如果还有网络请求嵌套的话,还可以继续往下写,在then方法里面再返回new Promise…,上面这种就是链式编程

1.1 什么情况下会用到Promise

一般情况下是有异步操作时,使用Promise对异步操作进行封装。
把网络请求塞到Promise里面,请求返回结果后调用resolve方法,然后在then方法里进行数据处理等操作。

new Promise(() => {})

new Promise的时候做了什么呢:
1、在构造函数里保存一些状态信息
2、执行传入的函数,也就是上面的箭头函数
3、在执行传入的回调函数时,会传入两个参数,分别是resolve和 reject,他们又是函数

new Promise((resolve, reject) => {
	// 网络请求
	setTimeout(() => {
		// 假设网络请求后返回的数据是 'Hello world'
		resolve('Hello world')
	}, 1000)
}).then((data) => { // 这里的这个data就是上面resolve方法传过来参数
	// 数据处理
	console.log(data);  // Hello World
})

Promise将网络请求的代码和最终处理数据的代码做了分离,这样看起来用Promise封装反而会让代码变得更多,但是当网络请求变的复杂时,当网络请求嵌套时,Promise的方式写出来的代码会更加的优雅和清晰。

2、resolve是成功时调用,reject是失败时调用

new Promise((resolve, reject) => {
	// 网络请求
	setTimeout(() => {
		// 成功时调用
		// 假设网络请求后返回的数据是 'Hello world'
		// resolve('Hello world')
		
		// 请求失败时调用
		reject('error message')
	}, 1000)
}).then((data) => { // 这里的这个data就是上面resolve方法传过来的参数
	// 数据处理
	console.log(data); 
	
}).catch((error) => { // 这里的这个error就是上面reject方法传过来的参数
	console.log(error); // error message
}) 

调用resolve后在then方法里接受参数进行处理;调用reject方法后在catch方法里接受参数进行处理

2.1 另一种方式(写法)

then 方法里面也可以接受两个参数,这两个参数都是函数。第一个函数是resolve时调用,第二个参数是reject时调用。

new Promise((resolve, reject) => {
	// 网络请求
	setTimeout(() => {
		resolve('Hello world')
		
		reject('error message')
	}, 1000)
}).then((data) => {
	console.log(data); // Hello world
}, (err) => {
	console.log(err); // error message
})

注意: 我上面的只是解释,真正写的时候,要么resolve,要么reject,他俩是互斥的,只会执行一个。


3、Promise简写方式

resolve 和 reject 两个参数,但是reject是可选参数,我们可以不写

new Promise(resolve => {
	setTimeout(() => {
		resolve('aaa')
	})
}).then((data) => {
	console.log(data); // aaa
	
	return new Promise(resolve => {
		resolve(data + 111);
	})
}).then(data => {
	console.log(data); // aaa111
})

我们发现上面代码的8、9、10行 返回的这个Promise里面并没有异步请求,只是单纯的resolve出去了一个数据而已,那么我们就可以进行简写:

new Promise(resolve => {
	setTimeout(() => {
		resolve('aaa')
	})
}).then((data) => {
	console.log(data); // aaa
	
	return Promise.resolve(data + 111); // 这是简写的样子
}).then(data => {
	console.log(data); // aaa111
})

但是我觉得上面的代码还是不够简洁,那么我们再简写:

new Promise(resolve => {
	setTimeout(() => {
		resolve('aaa')
	})
}).then((data) => {
	console.log(data); // aaa
	
	return data + 111; // 这是简写的样子
}).then(data => {
	console.log(data); // aaa111
	
	return data + 222;
}).then((data) => {
	console.log(data); // aaa111222
})

上面代码的第8行,直接return出去了数据,因为Promise内部在这里会进行一个Promise包装的,内部调了resolve方法,不用我们来做。


上述代码都是假设请求成功,调用了resolve方法,那么如果请求失败了呢,我们看下:

new Promise(resolve => {
	setTimeout(() => {
		resolve('aaa')
	})
}).then((data) => {
	console.log(data); // aaa
	
	return new Promise((resolve, reject) => {
		reject('出错了');
	})
}).then(data => {
	console.log(data); 
	
	return new Promise((resolve, reject) => {
		resolve(data + 222);
	})
}).then((data) => {
	console.log(data); 
}).catch((err) => {
	console.log(err);  // 出错了
})

我们发现只打印了 aaa 和 ‘出错了’, 其他的并没有执行。

那么我们的reject 也有简写:

new Promise(resolve => {
	setTimeout(() => {
		resolve('aaa')
	})
}).then((data) => {
	console.log(data); // aaa
	
	return Promise.reject('出错了'); // 简写
}).then(data => {
	console.log(data); 
	
	return data + 222;
}).then(data => {
	console.log(data); 
}).catch(err => {
	console.log(err);  // 出错了
})

4、Promise.all()

等多个网络请求都完成后再对数据进行处理。

Promise.all方法接受一个参数,这个参数是数组类型的,数组的每一项都是一个promise对象

Promise.all([
	new Promise((resolve, reject) => {
		$ajax({
			url: 'url1',
			success(data) {
				resolve(data)
			}
		})
	}),
	new Promise((resolve, reject) => {
		$ajax({
			url: 'url2',
			success(data) {
				resolve(data)
			}
		})
	})
]).then(results => {
	// 这个results是个数组,里面分别是第一个请求的返回结果,第二个请求的返回结果,第三个....
})

我们可以用延迟函数进行网络请求的模拟:

Promise.all([
	new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(111)
		}, 1000)
	}),
	new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(222)
		}, 2000)
	})
]).then(results => {
	// 这个results是个数组,里面分别是第一个请求的返回结果,第二个请求的返回结果,第三个....
	console.log(results); // [111, 222]
})
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值