浅谈ES6中Promise的使用

Promise 基础

官方文档:

api/new-promise.html

一篇讲解原理很好的文章:

认识和使用Promise,重构你的Js代码

Promise的出现是为了解决回调地狱. 减少代码的嵌套循环,转而写成类似于串联的代码.

如今绝大部分的浏览器都支持Promise了.我们可以在控制台中输出看一下.

在这里插入图片描述

可以看到Promise() 大写的P说明,这是一个构造函数.我们需要传入带有resolvereject的函数
而在prototype中我们也能看thencatch这两个函数.这两个函数是解决回调地狱的关键.
原理性的知识,可以移步我给的链接.下文主要结合代码讲一下使用.

Promise 使用

Promise 构造器

Promise是对异步操作进行处理,而JS的执行顺序是先执行主程序,后进行异步操作
为了方便演示, 使用了setTimeout()来模拟异步请求

先看一下下面的代码

new Promise((resolve, rejcet) => {
	setTimeout(() => {
		console.log('Promise')
	}, 2000)
	console.log('in Promise')
});

console.log('out Promise')

输出结果

in Promise
out Promise
Promise

如此,我们可以知道当 new Promise 时,里面的代码会立即执行.

那么如何让我们的代码在想要的适当的时机才去执行Promise里的操作呢?

我们可以将 new Promise写到一个函数中去,然后在需要的时候进行调用.例如下面的代码:

function testPromise() {
	return new Promise((resolve, rejcet) => {
		setTimeout(() => {
			console.log('Promise')
		}, 2000)
		console.log('in Promise')
	});
}
console.log('out Promise')
testPromise()

输出结果

out Promise
in Promise
Promise

构造器函数

new Promise((resolve, rejcet) => {... } 可以看到new Promise时传入了带有两个参数的函数.
其中 resolve 是当异步方法成功时执行的,而reject是失败时调用的

下面的代码中,我写了一个 定时器并结合 ajax()用来模拟一次异步请求,其中第一个参数flag用来模拟是否出现异常,
大家可以先大致了解一下,下面会讲到它的执行顺序

// 模拟ajax请求 第一个参数来模拟是否出现异常
function ajax(flag, err, data, resolve, reject) {
	// return 并不会起到返回的作用,只是为了代码到此结束
	if (flag == false)
		return reject(err)
	resolve(data)
}

function testPromise(err, data, flag) {
	return new Promise((resolve, reject) => {
		// 设置ajax(ture/false,...)来决定是否有异常
		setTimeout(ajax(flag, err, data, resolve, reject), 2000)
	})
}

testPromise('出错了 err', '没有错误,返回数据data', true)
	.then((data) => {
		console.log('----回调resolve :' + data)
	})
	.catch(err => {
		console.log('----回调reject :' + err)
	})

执行顺序

上面的代码,咋一看很是乱糟糟的,有些逻辑混乱.下面梳理一下执行的顺序

  • testPromise(‘出错了 err’, ‘没有错误,返回数据data’) 这行代码会调用testPromise(err, data)
  • 上一步中的 new Promise((resolve, reject) =>{}) 中的resolvereject并不会有任何值.并立即返回一个Promise对象
    • 此时,虽然返回了一个 Promise对象,但是 resolvereject 还是没有具体的函数的,只是起到占位作用.后面会进行注入
    • 而setTimeout(ajax(false, err, data, resolve, reject), 2000) 是一个延迟两秒的定时器,JS等2s会再执行它(模拟异步)
  • 接下来回到 .then(data=>{…}) then()会传入一个具体的函数来来执行成功后异步方法.也就是注入resolve,而.catch(err => {}) 会注入reject
  • 此时resolve, reject都拥有了具体的函数,上面的步骤都是JS会极快的完成的
  • 2s后,执行到setTimeout()
  • ajax()的flag==false 继而会执行 return reject(err) 就回调了.catch(err => {})
  • 输出console.log(’----回调reject :’ + err)

异步请求获取不到return 返回值

具体的使用

通过上面的代码和解释,我们已经看到Promise的特别之处,但是具体怎么才能解决回调地狱呢?

testPromise('出错了 err', '没有错误,返回数据data', true)
	.then((data) => {
		console.log('----回调resolve :' + data)
		return testPromise('哈哈哈,又错了', '这一次还没有错', true)
	})
	.then(data => {
		console.log('----回调resolve :' + data)
	})
	.catch(err => {
		console.log('----回调reject :' + err)
	})

输出结果

----回调resolve :没有错误,返回数据data
---回调resolve :这一次还没有错

必须还要返回一个Promise实例才可以再次使用.then()方法

这样,我们就可以看到原来代码的嵌套, 已经通过 .then() 串联到一起了.
只要上一个调用返回 Promise实例 ,就可以无限.then()下去

异常的处理

上面的代码都是通过 catch()进行异常捕获的.

function testPromise(err, data) {
	return new Promise((resolve, reject) => {
		// 设置ajax(ture/false,...)来决定是否有异常
		setTimeout(ajax(false, err, data, resolve, reject), 2000)
	})
}

testPromise('出错了 err', '没有错误,返回数据data')
	.then((data) => {
		console.log('----回调resolve :' + data)
		return testPromise('哈哈哈,又错了', '这一次还没有错')
	})
	.then(data=>{
		console.log('----回调resolve :' + data)
	})
	.catch(err => {
		console.log('----回调reject :' + err)
	})

输出结果:

----回调reject :出错了 err

结果是只输出了一次错误的
我们由此可以知道 catch() 是只要Promise执行链中出现一次异常,之后的的代码就不会执行了

那么我们如何让Promise执行链中如果出现异常后面的代码仍然执行呢?

其实.then(function(){},function(){} )

.then()可以传入两个函数

  • 第一个函数用来处理正常执行的函数是必须传的
  • 第二个函数用来处理异常,可以不穿.如果传了,.catch就不会进行处理,从而不影响Promise执行链
  • 这两个函数都需要返回一个 Promise 实例,才能延续执行链
testPromise('出错了 err', '没有错误,返回数据data', false)
	.then((data) => {
		console.log('----回调resolve :' + data)
		return testPromise('哈哈哈,又错了', '这一次还没有错', false)
	},err =>{
		console.log(err)
		return testPromise('哈哈哈,又错了', '这一次还没有错', false)
	})
	.then(data => {
		console.log('----回调resolve :' + data)
	})
	.catch(err => {
		console.log('----回调reject :' + err)
	})

输出结果

出错了 err
----回调reject :哈哈哈,又错了

axios

axios 是一个基于 promise 的 HTTP 库
它进行了很好的封装,尤其是一些常见的get,post请求.而且还有很好的拦截器机制
也有尤大神的推荐,因此大家可以了解一下.

axios中文说明

发布了92 篇原创文章 · 获赞 18 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_34120430/article/details/89416199