Promise定义
Promise:承诺者模式:它是ES6新增的一个内置类,基于Promise可以有效管理”异步编程”,避免回调地狱
- 语法:let p=new Promise([executor]) 语法 executor函数
- p是它的实例
- [executor]是一个函数,传递的不是函数会报错
- p.proto===Promise.prototype[所属类的原型]
- 实例私有属性:
- [[PromiseState]]:”pending”
- promise实例的状态有三种:
- pending准备状态 fulfilled/resolved成功状态 rejected失败状态
- 最初的状态是pending,后期基于某些操作可以把状态改变为fulfilled或者rejected
- (但是一但状态变为成功或者失败,则再也不能修改其状态了),
- promise实例的状态有三种:
- [[PromiseResult]]:undefined
- [[PromiseResult]]存放的是成功的结果或者失败的原因!
- [[PromiseState]]:”pending”
- 实例公有属性:then / catch / finally / Symbol.toStringTag=”Promise” [原型上]
- 实例私有属性:
疑惑一:状态改完有什么用
- 1)基于then可以存放两个函数 p.then(onfulfilled,onrejected)
- 2)当我们把状态修改为fulfilled成功态,则会把onfulfilled这个函数执行,相反,我们把状态修改为rejected失败态,则会把onrejected这个函数执行…
3) 并且会把[[PromiseResult]]作为实参值,传递给onfulfilled/onrejected
疑惑二:怎么改状态
1) new Promise的时候,会立即把传递进来的executor[承诺执行人]函数执行,并且会给executor传递两个实参进来
我们会用两个形参变量接收resolve/reject,并且值是两个函数
2)当我们执行resolve,promise实例状态变为fulfilled成功,传递的值就是成功的结果,赋值给[[PromiseResult]];
同理,只要把reject执行,promise实例状态变为rejected失败,传递的值就是失败的原因!
3) 如果executor函数执行报错了,则实例的状态也是rejected失败,失败原因是就是错误信息!
new Promise产生的实例,他的状态是成功还是失败,取决于“resolve/reject执行 或者 executor执行是否报错”
//========================>基础语法
let p=new Promise(function exector(resolve,reject){
console.log(1);//先输出1
resolve('OK');//promise实例状态变为fulfilled
});
console.log(p);
//p.then(onfulfilled,onrejected)
p.then(function onfulfilled(result){
//当状态为fulfilled的时候 会执行此函数
//result 存放的是成功结果 OK
},function onrejected(reason){
//当状态为rejected的时候,会执行此函数
//reason 失败的原因
});
基于Promise 管理异步编程的代码
```javascript new Promise((resolve, reject) => { $.ajax({
url: './api/data1.json', success(result) { resolve(result); //成功的时候把=》实例状态成功 }, error(reason) { reject(reason); }
}); }).then(result => { console.log(‘请求成功’, result);//成功做什么 }, reason => { console.log(‘请求失败’, reason);//失败做什么 });
//========================setTimeout异步
new Promise((resolve, reject) => { setTimeout(() => { let ran = Math.random(); if (ran > 0.5) resolve(‘OK’); reject(‘NO’); }, 1000); }).then(result => { console.log(‘请求成功’, result); }, reason => { console.log(‘请求失败’, reason); });
<a name="cFOqX"></a>
### 多次.then
> 我们可以基于 “promise实例.then” 存放多个onfulfilled/onrejected方法,状态变为成功或者失败,
> 存放的每一个对应的方法都会被执行
```javascript
let p1 = new Promise((resolve, reject) => {
resolve(100);//实例状态变为成功
});
p1.then(result => {
console.log(`成功:${result}`);//输出成功,100
}, reason => {
console.log(`失败:${reason}`);
});
p1.then(result => {
console.log(`成功:${result}`);//输出成功,100
}, reason => {
console.log(`失败:${reason}`);
});
new Promise产生的是实例 &执行then方法返回的实例
- new Promise产生的实例,他的状态是成功还是失败,取决于“resolve/reject执行 或者 executor执行是否报错”
- 每一次执行THEN方法,不仅存放了onfulfilled/onrejected方法,而且还会返回一个“全新的promise实例”
- 新实例p2的状态和值由谁来决定呢?
- 首先看返回值是否是一个新的Promise实例
- 不论onfulfilled/onrejected这两个方法执行的是哪一个,我们只看执行是否报错;
- 如果报错,则p2的状态是失败态rejected,值是报错原因!
- 如果不报错,则p2的状态是成功态fulfilled,值是函数的返回值!
let p1 = new Promise((resolve, reject) => { reject(0); }); let p2 = p1.then(result => { console.log(`成功:${result}`); return 1000; }, reason => { console.log(`失败:${reason}`); //失败 0 //没有报错代码 所以新实例的状态为成功 return -1000; }); let p3 = p2.then(result => { console.log(`成功:${result}`); //成功 -1000 throw new Error('xxx');//因为有错误信息,所以这个返回的实例是失败状态 }, reason => { console.log(`失败:${reason}`); }); p3.then(result => { console.log(`成功:${result}`); }, reason => { console.log(`失败:${reason}`); //失败 Error:xxx //失败就会执行reason });
.then 返回值是一个新的promise实例的特殊情况
特殊情况:我们之前说,不论onfulfilled/onrejected执行,只要不报错,则新实例p2的状态就是成功,只要报错就是失败…但是这里有一个特殊的情况:“执行不报错,但是返回值是一个新的promise实例,这样返回值的这个promise实例是成功还是失败,直接决定了p2是成功还是失败”let p1 = new Promise((resolve, reject) => { resolve(100); }); let p2 = p1.then(result => { console.log(`成功:${result}`); //成功 100 return new Promise((resolve, reject) => reject(-1000)); //执行了reject 所以状态为失败 }, reason => { console.log(`失败:${reason}`); return -1000; }); p2.then(result => { console.log(`成功:${result}`); }, reason => { console.log(`失败:${reason}`); //失败:-1000 });
``javascript let p1 = new Promise((resolve, reject) => { reject(0);//执行了失败的方法 }); let p2 = p1.then(result => { console.log(
成功:${result}); return new Promise((resolve, reject) => reject(-1000)); }, reason => { console.log(
失败:${reason}); //失败:0 //p1执行的是reject return new Promise((resolve, reject) => resolve(1000)); //成功 }); p2.then(result => { console.log(
成功:${result}); //成功:1000 }, reason => { console.log(
失败:${reason}`); });
- 新实例p2的状态和值由谁来决定呢?
<a name="JIE2w"></a>
## Promise中的then链机制
![](https://cdn.nlark.com/yuque/0/2021/webp/12917596/1621531811046-919a2e8a-d1db-4002-b718-e2735cf50e0d.webp#height=960&id=h7eNZ&originHeight=960&originWidth=1177&originalType=binary&ratio=1&size=0&status=done&style=none&width=1177)<br />![](https://cdn.nlark.com/yuque/0/2021/jpeg/12917596/1622701442724-b2f6a337-400e-455c-a4f7-9860b1e204a3.jpeg)<br />Promise中的then链机制:因为每一次.then都会返回一个新的promise实例,所以我们就可以持续.then下去了<br />而且因为实例诞生的方式不同,所以状态判断标准也不同<br /> **第一类:new Promise 出来的实例**
- 执行的是 resolve 还是 reject 决定状态
- executor函数执行是否报错
** 第二类:.then 返回的新实例**<br /> .then”执行会返回一个全新的promise实例“p2”:不论是then中的onfulfilled还是onrejected执行
- 首先看返回值是否为新的promise实例,
- 如果返回的是新的promise实例,则新的promise实例的状态和值,直接决定了.then返回的实例的状态和值
- 如果不是,则只看执行是否报错「不报错状态就是成功,值就是函数返回值;报错则状态就是失败,值就是失败原因」
** 第三类:把Promise当做对象**
- Promise.resolve(100) 返回一个状态是成功,值是100的新promise实例【值就是你传递实参进来的实参信息】
- Promise.reject(0) 返回一个状态是失败,值是0的新promise实例
只要实例的状态和值我们分析好,则 .then(onfulfilled,onrejected) 存放的方法,哪一个执行我们就知道了
```javascript
let p1 = new Promise((resolve, reject) => {
resolve(1);//更改p1的状态
reject(0);
});
let p2 = p1.then(function onfulfilled(result) {
//执行onfulfilled =>没有报错 没有返回值 则p2的状态是成功 值是undefined
}, function onrejected(reason) {
});
p2.then(function onfulfilled(result) {
console.log(result);//结果是undefined
}, function onrejected(reason) {
});
思考题
Promise.resolve(100).then(result => {
console.log(`成功:${result}`);//100
return result / 10;
}, reason => {
console.log(`失败:${reason}`);
return Promise.resolve(200);
}).then(result => {
console.log(`成功:${result}`);//10
return Promise.reject(300);
}, reason => {
console.log(`失败:${reason}`);
return reason / 20;
}).then(result => {
console.log(`成功:${result}`);
return 0;
}, reason => {
console.log(`失败:${reason}`);//300
return 1;
}).then(result => {
console.log(`成功:${result}`);//成功1
}, reason => {
console.log(`失败:${reason}`);
});
Promise.resolve(Promise.reject(100)); //传递的值是失败的promise实例
// 状态:fulfilled
// 值:新的实例 -> 状态:rejected 值:100 */
Promise.resolve(10).then(result => {
console.log(`成功:${result}`); //成功 10
return Promise.resolve(Promise.reject(100));
//如果实例的状态是成功状态,需要把它的值再次处理一遍,以最后一个值处理的结果为准
}).then(result => {
console.log(`成功:${result}`);
}, reason => {
console.log(`失败:${reason}`); //失败:100
});
//===========================
Promise.resolve(10).then(result => {
console.log(`成功:${result}`); //成功:10
return Promise.reject(Promise.resolve(100));
}).then(result => {
console.log(`成功:${result}`);
}, reason => {
console.log(`失败:${reason}`); //失败:[object Promise]
});
以上总结:如果执行onfulfilled或者onrejected的时候,返回的值是是一个promise实例“@P”,
我们之前说“@P”是成功还是失败,直接决定了“p2(.then返回的新实例)”是成功还是失败…但是这样是不严谨的,
- 按照官方规范要求:
- 如果@P是成功状态,需要把它的值再次处理一遍…
- 如果@P是失败的,直接认定为失败的状态,不需要把失败的值再次处理…
then链的穿透性(顺延)
正常情况下,.then的时候会传递两个函数onfulfilled/onrejected,但是有些时候,我们是不传递其中的某个函数的,这种情况下我们需要采取“顺延策略”:找到下一个then中对应状态的函数执行 例如:.then(null,onrejected) 【只处理失败】或者 .then(onfulfilled)【只处理成功】
Promise.reject(0).then(result => {
console.log(`成功:${result}`);
return 1;
}).then(result => {
console.log(`成功:${result}`);
return 2;
}).then(result => {
console.log(`成功:${result}`);
return 3;
}, reason => {
console.log(`失败:${reason}`); //失败:0
});
//==================
Promise.resolve(100).then(result => {
console.log(`成功:${result}`); //成功:100
throw '我失败了'; //自己抛出异常
}).then(result => {
console.log(`成功:${result}`);
return 2;
}).then(result => {
console.log(`成功:${result}`);
return 3;
}, reason => {
console.log(`失败:${reason}`); //失败:我失败了 顺延至最后一个reason
});
//======================
Promise.resolve(100).then(result => {
console.log(`成功:${result}`); //成功:100
return 1;
}).then(result => {
console.log(`成功:${result}`); //成功:1
return Promise.reject('NO');
}).then(null, reason => {
console.log(`失败:${reason}`); //失败:NO
});
Promise.catch
.catch(onrejected) 相当于==> .then(null,onrejected) 真实项目中,我们经常:then中只传递onfulfilled,处理状态是成功的事情;在then链的末尾设置一个catch,处理失败的事情(依托于then链的穿透机制,无论最开始还是哪个then中,出现了让状态为失败的情况,都会顺延到最末尾的catch部分进行处理)
Promise.resolve(100).then(result => {
console.log(`成功:${result}`); //成功:100
return 1;
}).then(result => {
console.log(`成功:${result}`); //成功:1
return Promise.reject('NO');
}).catch(reason => {
console.log(`失败:${reason}`); //失败:NO
});
JS中的异常捕获
作用
TRY/CATCH的作用:捕获异常信息,不影响下面的代码执行;还可以收集错误信息,发送给后台做统计等
try中尝试执行代码,如果执行不报错,则不走catch,如果执行报错,直接进入到catch中,而且err接收的就是报错信息…但是不论报错与否,finally都会执行
try {
console.log(a);
} catch (err) {
console.log(err); //ReferenceError: a is not defined
} finally {
console.log('哈哈,我是个傻子'); //哈哈,我是个傻子
}
try {
let a = 10;
console.log(a); //10 输出10 不会执行catch方法
} catch (err) {
console.log(err);
} finally {
console.log('哈哈,我是个傻子'); //哈哈,我是个傻子
}
/* console.log(a); //Uncaught ReferenceError: a is not defined 报错了,下面代码则不再执行
console.log('OK'); */
try {
console.log(a);
} catch (err) {}
console.log('OK'); //OK
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到。