promise
定义:
ES6新增的内置类,它是“承诺者模式”,主要是为了有效管理异步编程,避免“回调地狱”
- 不兼容IE浏览器,如果想在IE当中使用她,需要基于ES5重写Promise「Promise A+规范 && 也可以基于babel/polyfill处理」
语法:
let p1 = new Promise([executor]);
[executor]
-
必须传递的是函数,不传或者传递其他类型值都会报错
-
new Promise的时候,会立即把传递的[executor]函数执行,这个操作是同步的
-
[executor]函数中
@1 一般用来写一些异步的编程代码(promise管理异步编程,其实就是把异步编程的代码放在[executor]中) @2 [executor]函数中有两个形参:resolve / reject 1) 本身也是函数 2)resolve([value])把实例的状态改为fulfilled,实例值是[value] 3)reject([reason]),把实例的状态改为reject,实例值是[reason] 4)一旦实例的状态被改变为失败或者成功,不可以再次更改 -
[executor]函数执行一旦报错,实例的状态也是rejected,实例的值是报错原因
[p1 是 Promise类的一个实例]
-
私有属性
-
[[PromiseState]]:"pending" 实例的状态 -
’pending‘最开始的默认值(准备状态) -
‘fulfilled’或者‘resolved’ 成功态 -
‘rejected’失败状态 -
[[PromiseResult]]:undefined 实例的结果(存储成功的结果或者失败的原因)
-
-
公有方法 Promise.prototype
-
then -
catch -
finally -
symbol.toStringTag:"Promise"
new Promise();
`let p1 = new Promise((resolve,reject)=>{
resolve(100)
});
let p2 ==p1.then((value)=>{
},
(reason)=>{
});
p2.then(
(value)=>{};
(reason)=>{}
) `
p1.then语法
p1.then([onfuifilled],[onrejected])
- [onfuifilled]和 [onrejected]一般都是一个函数
- 当实例的状态是fulfilled的时候,则会吧onfuifilled]的方法执行;实例状态是rejected的时候,则会吧[onrejected]的方法执行,如果实例状态还是pending,两个方法暂时都不会执行,只有等到等待状态修改后再执行对应方法
- 两个函数中的value或者reason存储的都是[[PromiseResult]]实例的结果~
执行then方法会返回一个全新的promise实例「例如p2」
- 如何确定p2是成功还是失败的? 有P1.then 传入的[onfuifilled]或者[onrejected]任何一个方法执行决定
@1 看方法执行是否报错,如果报错,则p2状态是rejected,值是报错的原因;如果没有报错则继续……
@2 看方法执行的返回值是否是一个新的promise实例(别名:@PE),如果并没有返回新promise实例,则P2的状态是fulfilled,值是返回的值!!
如果@PE是一个promise实例,则@PE的状态和值,直接决定来P2的状态和值!!
创建promise实例的4种方法
-
let p1 = new Promise((resolve,reject)=>{ resolve(100)});
-
let p2 ==p1.then
-
promise.resolve([value])创建一个状态是fulfilled,值得[value]的实例
-
promise.reject([reason])创建一个状态是rejected,值得[reason]的实例
then 链具备‘穿透性’
如果onfuifilled或者onrejected没有设置,则会顺延到下一个then对应的onfulfilled或者onfejected上
- 原理:我们没有设置,promise内部会默认进行设置,以此来实现顺延
catch
-
promise实例.catch([onrejected])等价于.then(null,[onrejected])
-
真实项目中:then一般只写onfulfilled方法,在整个“链”最末尾加一个catch处理失败,这样不论哪一次then中的方法执行结果是失败,都会走到最后一个catch中;如果实例状态是失败,但是我们没有设置任何失败处理的函数,则浏览器会抛出这个红色的错误,但是不会影响其他代码的处理!!
`Promise.reject(0) .then(value=>{ console.log('成功', value) return value*10 }) .then(value=>{ console.log('成功', value) return value*10 }) .then(value=>{ console.log('成功', value) return value*10 }) .catch(reason=>{ console.log('失败',reason) })`
all,any,race
传递一个数组,数组中包含多个promise 实例,最后返回一个新的promise实例(别名:_NEW)
-
数组中某一项并不是promise实例,内部会把其处理为状态是成功,值是这个值的promise实例
-
返回的新实例_NEW是成功还是失败?
-
promise.all 集合中所有实例都成功,整体(_NEW)才是成功,只要有一个失败,整体就是失败!! -
promise.any 集合中只要有一个成功,则整体就成功,除非所有的都失败,整体才失败!! -
promise.race 看集合中谁第一个计算出结果和状态。那么他的状态和结果就是整体的状态和结果!!
-
Let _NEW = promise.all([promise1,promise2,...])
Let _NEW = promise.any([promise1,promise2,...])
Let _NEW = promise.race([promise1,promise2,...])
promise 执行的情况
示例
`let p1 = new Promise(resolve =>{
resolve('ok')//立即修改了P1的状态和值「同步」
});
console.log(3)
p1.then(value=>{
console.log('成功',value)
},reason=>{
console.log('失败',value)
})
console.log(4)`
详解
promise.then(onfuifilled,onrejected)
情况一:
调用then的时候,promise的状态是已经知道成功或者失败的,也并不会把onfuifilled 和onrejected 立即执行,而是创建一个”异步的微任务“「先进入WebAPI中监听,发现后期肯定可以执行,则挪至到EventQueue中排队等着...等待同步代码执行完,在按照顺序执行异步任务」
情况二:
调用then的时候,promise的状态是pending,此时我们需要先把onfuifilled 和onrejected存储到对应的容器当中,同时把让“两个方法中的一个执行”这件事放在WebAPI中去监听,同步代码继续执行……
当后期我们清楚的知道promise是成功还是失败的「例如:resolve和reject方法执行……」,把之前放在WebAPI中监听的任务,挪至到“异步的微任务队列中”排队等着(并不会立即执行)
为什么会有promise?promise可以有效管理异步编程
ajax请求(目的:从服务器获取数据,实现和服务器端的数据通信)
- ajax串行:多个请求之间有依赖,只有完成上一个请求,才能发送在一个请求
- ajax并行:多个请求之间并没有任何关系,此时我们可以同时发送多个请求,谁先请求回来数据,就先处理谁「额外的需求,同时发送多个请求,当所有的请求都成功,我们想要做啥事……」。
串行回调地狱example: 需求:三个请求借口:( ),对于异步编程来讲,如果基于回调函数的方式来处理异步成功后的相关操作,非常容易产生回调地狱,代码看起来太‘恶心’
` $.ajax({
url:'/api/list'
success(){
//第一个请求成功,触发success回调函数
$.ajax({
url:'/api/detail?id=100'
success(){
//第二个请求成功,触发success回调函数
$.ajax({
})
}
})
}
})
` 为了避免回调地狱的写法:
axios.get返回的是pormise 的实例,所以基于promise可以有效管理异步编程
` axios.get('/api/list')
.then(()=>{
//第一个请求成功
return axios.get('/api/detail?id=100');
})
.then(()=>{
//第二个请求成功
return axios.get('/api/paiming')
})
.then(()=>{
//第三个请求成功
})`
more sweet:
基于async/await语法糖,实现出把异步改为同步的效果
`async()=>{
await axios.get('')
await axios.get('')
await axios.get('')
}) `