Promise的用法
Posted xfy196
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise的用法相关的知识,希望对你有一定的参考价值。
Promise
Promise是什么?
- 主要用异步计算
- 可以异步操作队列化,按照期望的顺序执行,返回符合的数据
- 可以再对象之间传递和操作promise,帮我们处理队列
为什么会有Promise呢?
为了避免任务冻结
- 同步:假设你去了一家饭店,找个位置,叫来服务员,这个时候服务员对你说,对不起我是“同步”服务员,我要服务完这张桌子才能招呼你。那桌客人明明已经吃上了,你只是想要个菜单,这么小的动作,服务员却要你等到别人的一个大动作完成之后,才能再来招呼你,这个便是同步的问题:也就是“顺序交付的工作1234,必须按照1234的顺序完成”。
- 异步:则是将耗时很长的A交付的工作交给系统之后,就去继续做B交付的工作,。等到系统完成了前面的工作之后,再通过回调或者事件,继续做A剩下的工作。AB工作的完成顺序,和交付他们的时间顺序无关,所以叫“异步”。
异步操作常见的语法
- 事件监听
<script>
document.addEventListener("click", function(){
console.log("你点击了我");
});
</script>
- ajax请求的回调函数
<script>
ajax("https://www.baidu.com", {
success : function(data){
// 必须在ajax请求成功的时候才会执行这个成功函数回调函数
console.log(data);
}
});
</script>
- 定时器 延时器
<script>
setInterval(function () {
// 没过一秒钟执行一次
console.log("hello");
}, 1000);
setTimeout(function () {
// 页面加载之后延迟一秒后执行
console.log("hello");
}, 1000);
</script>
异步回调的问题
- 之前处理异步是通过纯粹的回调函数的形式进行处理的
- 很容易进入回调地狱中,同时回调地狱中剥夺了函数的return的能力
- 问题可以解决,但是难以读懂,维护困难
- 容易进入回调地狱-嵌套层次深-不好维护
一般情况下,我们一次调用API就可以完成请求。
有些情况我们需要多次调用服务器API,就会形成一个链式调用,比如为了完成一个功能,我们需要调用API1,API2,API3,依次按照顺序进行调用,这个时候就会出现回调地狱的问题。
promise
- promise是一个对象,他可以用来保存状态。
- 并剥夺return的能力,因此无需层层传递callback,进行回调获取数据
- 代码风格,容易理解,便于维护。
- 使用多个异步等待合并便于解决
promise详解
new Promise( ( resolve, reject ) => {
resolve("成功");
} ).then(
res => {
console.log(res);
},
error => {
console.log(error);
}
);
-
resolve作用是将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
-
promise有三个状态:
- pending : 初始化状态
- fulfilled : 操作成功状态
- rejected : 失败状态
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。 -
Promise状态改变,只有两种情况
从pending变为fulfilled
从pending变为rejected
最简单的案例
new Promise(resolve => {
setTimeout(() => {
resolve(‘hello‘)
}, 2000)
}).then(res => {
console.log(res)
})
分两次,顺序执行
new Promise(resolve => {
setTimeout(() => {
resolve(‘hello‘)
}, 2000)
}).then(val => {
console.log(val) // 参数val = ‘hello‘
return new Promise(resolve => {
setTimeout(() => {
resolve(‘world‘)
}, 2000)
})
}).then(val => {
console.log(val) // 参数val = ‘world‘
})
结论:promise作为队列最为重要的特性,我们在任何一个地方生成了一个promise队列之后,我们可以把他作为一个变量传递到其他地方。
Promise.all()批量处理
Promise.all([p1, p2, p3])用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise
它接收一个数组作为参数
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
当所有的子Promise都完成,该Promise完成,返回值是全部值得数组
有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果
//切菜
function cutUp(){
console.log(‘开始切菜。‘);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log(‘切菜完毕!‘);
resolve(‘切好的菜‘);
}, 1000);
});
return p;
}
//烧水
function boil(){
console.log(‘开始烧水。‘);
var p = new Promise(function(resolve, reject){ //做一些异步操作
setTimeout(function(){
console.log(‘烧水完毕!‘);
resolve(‘烧好的水‘);
}, 1000);
});
return p;
}
Promise.all([cutUp(), boil()])
.then((result) => {
console.log(‘准备工作完毕‘);
console.log(result);
})
Promise.race()类似于Promise.all(),只不过他是只需要一个成功就算全部状态成功(返回第一个成功状态的结果)
let p1 = new Promise(resolve => {
setTimeout(() => {
resolve(‘I`m p1 ‘)
}, 1000)
});
let p2 = new Promise(resolve => {
setTimeout(() => {
resolve(‘I`m p2 ‘)
}, 2000)
});
Promise.race([p1, p2])
.then(value => {
console.log(value)
})
-
常见用法:
异步操作和定时器在一起,如果定时器先触发那告知用户超时
-
现实中的用法
回调包装成Promise,他有两个显而易见的好处
- 可读性好
- 返回的结果可以加入其它的Promise队列进行操作
回调地狱的代码和Promise的代码对比
/***
第一步:找到北京的id
第二步:根据北京的id -> 找到北京公司的id
第三步:根据北京公司的id -> 找到北京公司的详情
目的:模拟链式调用、回调地狱
***/
// 回调地狱
// 请求第一个API: 地址在北京的公司的id
$.ajax({
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city‘,
success (resCity) {
let findCityId = resCity.filter(item => {
if (item.id == ‘c1‘) {
return item
}
})[0].id
$.ajax({
// 请求第二个API: 根据上一个返回的在北京公司的id “findCityId”,找到北京公司的第一家公司的id
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list‘,
success (resPosition) {
let findPostionId = resPosition.filter(item => {
if(item.cityId == findCityId) {
return item
}
})[0].id
// 请求第三个API: 根据上一个API的id(findPostionId)找到具体公司,然后返回公司详情
$.ajax({
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company‘,
success (resCom) {
let comInfo = resCom.filter(item => {
if (findPostionId == item.id) {
return item
}
})[0]
console.log(comInfo)
}
})
}
})
}
})
// Promise 写法
// 第一步:获取城市列表
const cityList = new Promise((resolve, reject) => {
$.ajax({
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city‘,
success (res) {
resolve(res)
}
})
})
// 第二步:找到城市是北京的id
cityList.then(res => {
let findCityId = res.filter(item => {
if (item.id == ‘c1‘) {
return item
}
})[0].id
findCompanyId().then(res => {
// 第三步(2):根据北京的id -> 找到北京公司的id
let findPostionId = res.filter(item => {
if(item.cityId == findCityId) {
return item
}
})[0].id
// 第四步(2):传入公司的id
companyInfo(findPostionId)
})
})
// 第三步(1):根据北京的id -> 找到北京公司的id
function findCompanyId () {
let aaa = new Promise((resolve, reject) => {
$.ajax({
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list‘,
success (res) {
resolve(res)
}
})
})
return aaa
}
// 第四步:根据上一个API的id(findPostionId)找到具体公司,然后返回公司详情
function companyInfo (id) {
let companyList = new Promise((resolve, reject) => {
$.ajax({
url: ‘https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company‘,
success (res) {
let comInfo = res.filter(item => {
if (id == item.id) {
return item
}
})[0]
console.log(comInfo)
}
})
})
}
以上是关于Promise的用法的主要内容,如果未能解决你的问题,请参考以下文章