Promise的详解优缺点举例⼦
Promise 的详解优缺点举例⼦
⾸先说明这个⼤部分是抄的,因为这个我也是在学,所以是肯定的,哈哈哈。但是能抄让别⼈更理解,那就是抄的真他妈棒
这个promise⼀般接触就是在请求的时候,返回值的相应操作,回调展⽰,处理相应的信息
介绍:
0、是个异步的操作对象(对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
1、主要⽤于异步计算
2、可以将异步操作队列化,按照期望的顺序执⾏,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
优缺点:
---Promise 优点:
有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统⼀的接⼝,使得控制异步操作更加容易。
---Promise 缺点:
⾸先,⽆法取消 Promise,⼀旦新建它就会⽴即执⾏,⽆法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,⽆法得知⽬前进展到哪⼀个阶段(刚刚开始还是即将完成)。
异步操作的常见语法
事件监听:
function start() {
// 响应事件,进⾏相应的操作
}
// jquery on 监听
$('#start').on('click', start)
⽅法回调:
// ⽐较常见的有ajax
$.ajax('www.wyunfei/', {
success (res) {
// 这⾥可以监听res返回的数据做回调逻辑的处理
}
})
// 或者在页⾯加载完毕后回调
$(function() {
// 页⾯结构加载完成,做回调逻辑处理
})
这样操作有啥不好、
1.之前处理异步是通过纯粹的回调函数的形式进⾏处理
2.很容易进⼊到回调地狱中,剥夺了函数return的能⼒
3.问题可以解决,但是难以读懂,维护困难
4.稍有不慎就会踏⼊回调地狱 - 嵌套层次深,不好维护
有些情况需要多次调⽤服务器API,就会形成⼀个链式调⽤,⽐如为了完成⼀个功能,我们需要调⽤API1、API2、API3,依次按照顺序进⾏调⽤,这个时候就会出现回调地狱的问题
API3,依次按照顺序进⾏调⽤,这个时候就会出现回调地狱的问题
详解使⽤Promise:
new Promise(
function (resolve, reject) {
// ⼀段耗时的异步操作
resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
1、resolve作⽤是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调⽤,并将异步操作的结果,作为参数传递出去;
2、reject作⽤是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调⽤,并将异步操作报出的错误,作为参数传递出去。
3、promise有三个状态:
1.pending[待定]初始状态
2.fulfilled[实现]操作成功
当promise状态发⽣改变,就会触发then()⾥的响应函数处理后续步骤;
promise状态⼀经改变,不会再变。
4、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完成后then()
let pro = new Promise(resolve => {
setTimeout(() => {
resolve('hello world')
}, 2000)
})
setTimeout(() => {
pro.then(value => {
console.log(value) // hello world
})
}, 2000)
结论:promise作为队列最为重要的特性,我们在任何⼀个地⽅⽣成了⼀个promise队列之后,我们可以把他作为⼀个变量传递到其他地⽅。
其他情况论证:
假如在.then()的函数⾥⾯不返回新的promise,
.then()
1、接收两个函数作为参数,分别代表fulfilled(成功)和rejected(失败)
2、.then()返回⼀个新的Promise实例,所以它可以链式调⽤
3、当前⾯的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执⾏
4、状态响应函数可以返回新的promise,或其他值,不返回值也可以我们可以认为它返回了⼀个null;
5、如果返回新的promise,那么下⼀级.then()会在新的promise状态改变之后执⾏
6、如果返回其他任何值,则会⽴即执⾏下⼀级.then()
.then()⾥⾯有.then()的情况
1、因为.then()返回的还是Promise实例
2、会等⾥⾯的then()执⾏完,再执⾏外⾯的
举例⼦:
对于我们来说,此时最好将其展开,也是⼀样的结果,⽽且会更好读:
错误处理:
第⼀种抛异常:
new Promise(resolve => {
setTimeout(() => {
throw new Error('error')
}, 2000)
}).then(res => {
console.log(res)
}).catch(error=> {
console.log('error',error)
})
第⼆种返回失败:
new Promise(resolve => {
setTimeout(() => {
reject('error')
}, 2000)
}).then(res => {
console.log(res)
}),(error) => {
console.log('error',error)
})
第⼀种:throw new Error('错误信息').catch( () => {错误处理逻辑})
第⼆种:reject('错误信息').then(() => {}, () => {错误处理逻辑})
推荐使⽤第⼀种⽅式,更加清晰好读,并且可以捕获前⾯所有的错误(可以捕获N个then回调错误)
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 => {
.then(value => {
console.log(value)
})
常见⽤法:
异步操作和定时器放在⼀起,,如果定时器先触发,就认为超时,告知⽤户;
例如我们要从远程的服务家在资源如果5000ms还没有加载过来我们就告知⽤户加载失败
现实中的⽤法
回调包装成Promise,他有两个显⽽易见的好处:
1、可读性好
2、返回的结果可以加⼊任何Promise队列
让我说⼀下:
然后不明⽩的⼈还是不明⽩,为啥要⽤这个东西啊,⾸先他是个异步的,所以对于js来说,你要同时去做两件事情的时候,那是很棒的,所以举例⼦:你有个需求,获取中国某⼀个村的详情,所以你要先请求数据拿到中国所有的省,然后拿到你要的省的编号,去请求所有的镇,然后拿到镇的编号,去中国所有村的列表⾥⾯进⾏查。结果就是,axios⼀串回调,但是要⽤promise的时候就不是了,你可以把获取村的列表和查编号的过程同时进⾏。避免回调地狱
Promise 对⽐回调:
代码⽰例:回调
/***
第⼀步:到北京的id
第⼆步:根据北京的id -> 到北京公司的id
第三步:根据北京公司的id -> 到北京公司的详情
⽬的:模拟链式调⽤、回调地狱
***/
// 回调地狱
// 请求第⼀个API: 地址在北京的公司的id
$.ajax({
url: 'www.easy-mock/mock/5a52256ad408383e0e3868d7/lagou/city',
success (resCity) {
let findCityId = resCity.filter(item => {
if (item.id == 'c1') {
return item
}
})[0].id
$.ajax({
pending// 请求第⼆个API: 根据上⼀个返回的在北京公司的id “findCityId”,到北京公司的第⼀家公司的id
url: 'www.easy-mock/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: 'www.easy-mock/mock/5a52256ad408383e0e3868d7/lagou/company',
success (resCom) {
let comInfo = resCom.filter(item => {
if (findPostionId == item.id) {
return item
}
})[0]
console.log(comInfo)
}
})
}
})
}
})
代码⽰例:Promise
// Promise 写法
// 第⼀步:获取城市列表
const cityList = new Promise((resolve, reject) => {
$.ajax({
url: 'www.easy-mock/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: 'www.easy-mock/mock/5a52256ad408383e0e3868d7/lagou/position-list',
success (res) {
resolve(res)
}
})
})
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论