一、基础
1、特点
- 分为三个阶段
- pending:初始状态,非 成功 / 失败 状态
- fulfilled(resolved):操作成功
- rejected:操作失败
- 阶段不会自动改变,需要手动调用
_new promise(function(_**_resolve, reject_**_){})_
中的 resolve()将状态更改为 fulfilled,以及 rejected() 将状态更改为 rejected - 一旦状态被改变,就无法再改变(状态终生只能改变一次)
```javascript
// 先把 promise 的状态改为失败,再尝试改为成功
// 最后结果仍未失败状态,因为状态只能变更一次,第二次改成功状态无效
let foo = () => {
return new Promise((resolve, reject) => {
}); }reject('操作失败!');
resolve('操作成功!');
let successFun = data => { console.log(‘成功回调!!,数据为:’ + data); }
let p = foo().then(successFun, null);
console.log(p);
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22695934/1637913848108-d019129d-1ae7-4372-bb97-5d045c5af07c.png#clientId=uf250581b-71fa-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=112&id=u0ebc632a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=112&originWidth=306&originalType=binary&ratio=1&rotation=0&showTitle=true&size=7509&status=done&style=shadow&taskId=uf49852c2-1f14-4291-800a-f98b8b58558&title=%E7%8A%B6%E6%80%81%E5%8F%98%E6%9B%B4&width=306 "状态变更")
- 若错过了状态变更的第一时间,之后再去监听变更,也能获取到结果(对比事件 event,事件若错过了第一时间,之后再去获取事件是获取不到的)
```javascript
// 下面代码,未第一时间监听到 promise 状态的改变
// 但输出结果仍能正常监听
let foo = () => {
return new Promise((resolve, reject) => {
resolve('123');
reject('操作失败!');
});
}
let successFun = data => {
console.log('成功回调!!,数据为:' + data);
}
let p = foo();
setTimeout(() => {
console.log('计时器函数执行!');
p.then(successFun, null);
}, 2000);
console.log('外部代码执行完毕!');
2、优点
- 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
- promise 对象提供了统一的接口,使得控制异步操作更加容易
3、缺点
- 无法取消 promise,一旦新建它就会立即执行
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
}); }console.log('Promise 对象被新建了!');
foo(); console.log(‘同步的代码!’);
// 输出顺序如下,说明 promise 一旦创建就会立即执行 // Promise 对象被新建了! // 同步的代码!
- 若不设置回调函数,promise 内部抛出的异常无法被外部捕获
```javascript
// 首先看正常的代码
throw new Error('外部抛出异常!');
console.log('同步的代码!');
// 一旦出现了异常,之后的代码就不会执行
// 再看 promise,异常会正常抛出,但不会阻止外部代码正常执行
let foo = () => {
return new Promise((resolve, reject) => {
console.log('Promise 对象被新建了!');
throw new Error('内部抛出异常!');
});
}
let p = foo();
console.log('同步的代码!');
// 另外
- 当 promise 处于 pending 阶段时,无法得知目前进展到哪个阶段(刚开始还是即将完成)
二、用法
1、基础用法
- 通过
**_resolve(data)_**
**_reject(data)_**
变更 promise 的状态,同时 data 数据即为外部监听器得到的数据 ```javascript let foo = () => { return new Promise((resolve, reject) => {
}); }let data = { name: '军大侠', sex: '男' } resolve(data);
let successFun = data => { console.log(‘成功回调!!必须有成功回调函数’); console.log(data); } let failFun = data => { console.log(‘失败回调!!失败回调函数可为空’); }
let p = foo(); p.then(successFun, null);
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22695934/1637914530007-ec782d2c-2144-4a84-89e4-583810804b01.png#clientId=uf250581b-71fa-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=68&id=ucd41bf57&margin=%5Bobject%20Object%5D&name=image.png&originHeight=68&originWidth=228&originalType=binary&ratio=1&rotation=0&showTitle=true&size=4000&status=done&style=shadow&taskId=uaef38aa7-3989-4697-b326-ad14d13c41b&title=%E7%9B%91%E5%90%AC%E5%99%A8&width=228 "监听器")
<a name="cXd9D"></a>
#### 2、回调函数执行顺序
- 无论 promise 的状态是何时改变的,回调函数永远是最后执行
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
console.log('内部开始执行!');
resolve();
console.log('内部执行完毕!');
});
}
let successFun = data => {
console.log('成功回调!!');
}
foo().then(successFun, null);
console.log('外部执行完毕!!');
- 回调函数的优先级高于计时器(前者属于js引擎,后者属于浏览器API)
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
}); }console.log('内部开始执行!'); resolve(); console.log('内部执行完毕!');
let successFun = data => { console.log(‘成功回调!!’); }
setTimeout(() => { console.log(‘计时器即时输出!!’); }, 0); foo().then(successFun, null); console.log(‘外部执行完毕!!’);
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22695934/1637915286669-cc499bd5-f5f0-4f8c-be40-80f7d5ef0d61.png#clientId=u9f868d9c-93ef-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=129&id=u438021b7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=129&originWidth=170&originalType=binary&ratio=1&rotation=0&showTitle=true&size=2867&status=done&style=shadow&taskId=u17c564c0-1b05-4cc1-a995-130a0757b7d&title=%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E4%BC%98%E5%85%88%E7%BA%A7%E6%9B%B4%E9%AB%98&width=170 "回调函数优先级更高")
<a name="jOxwI"></a>
#### 3、链式编程
- 原理:每个 promise 的 then 中,返回一个新的 promise
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的数据!');
}, 1000);
});
}
foo().then(data => { // 第一个 promise 的监听
return new Promise((res, rej) => {
res(data += "11")
})
}).then(data => { // 第二个 promise 的监听
return new Promise((res, rej) => {
res(data += "22");
})
}).then(data => { // 第三个 promise 的监听
console.log(data);
})
- 上述代码可以简写成如下
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
}); }setTimeout(() => { resolve('成功的数据!'); }, 1000);
foo().then(data => { // 第一个 promise 的监听 return Promise.resolve(data += “11”); }).then(data => { // 第二个 promise 的监听 return Promise.resolve(data += “22”); }).then(data => { // 第三个 promise 的监听 console.log(data); })
- 甚至可以再简化
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的数据!');
}, 1000);
});
}
foo().then(data => { // 第一个 promise 的监听
return data += "11"
}).then(data => { // 第二个 promise 的监听
return data += "22"
}).then(data => { // 第三个 promise 的监听
console.log(data);
})
- 但 reject 的简化方法只有
**_return Promise.reject(data += "11")_**
- 当 then 未指定处理 rejected 状态的失败函数时,会抛出异常
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
}); }setTimeout(() => { resolve('成功的数据!'); }, 1000);
foo().then(data => { // 第一个 promise 的监听 return data += “11” }).then(data => { // 第二个 promise 的监听 return Promise.reject(data += “22”); }).then(data => { // 第三个 promise 的监听 console.log(data); })
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22695934/1637918355511-34047a26-7695-4399-8651-1f25c3bb2811.png#clientId=u9f868d9c-93ef-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=76&id=ubf4f4b6c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=76&originWidth=337&originalType=binary&ratio=1&rotation=0&showTitle=true&size=3174&status=done&style=shadow&taskId=u6f33a6fa-5a20-4e8c-9bd3-c9407705ec0&title=%E6%9C%AA%E6%8C%87%E5%AE%9A%E5%A4%B1%E8%B4%A5%E5%87%BD%E6%95%B0%EF%BC%8C%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8&width=337 "未指定失败函数,抛出异常")
- 指定了失败处理函数时,则会执行失败处理函数
```javascript
let foo = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的数据!');
}, 1000);
});
}
foo().then(data => { // 第一个 promise 的监听
return data
}).then(data => { // 第二个 promise 的监听
return Promise.reject();
}).then(data => { // 第三个 promise 的监听
console.log("成功!!");
}, () => {
console.log('失败!!');
})