一、基础

1、特点

  • 分为三个阶段
    • pending:初始状态,非 成功 / 失败 状态
    • fulfilled(resolved):操作成功
    • rejected:操作失败
  • 阶段不会自动改变,需要手动调用 _new promise(function(_**_resolve, reject_**_){})_ 中的 resolve()将状态更改为 fulfilled,以及 rejected() 将状态更改为 rejected
  • 一旦状态被改变,就无法再改变(状态终生只能改变一次) ```javascript // 先把 promise 的状态改为失败,再尝试改为成功 // 最后结果仍未失败状态,因为状态只能变更一次,第二次改成功状态无效 let foo = () => { return new Promise((resolve, reject) => {
    1. reject('操作失败!');
    2. 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('外部代码执行完毕!');

image.png

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('同步的代码!');

// 一旦出现了异常,之后的代码就不会执行

image.png

// 再看 promise,异常会正常抛出,但不会阻止外部代码正常执行
let foo = () => {
    return new Promise((resolve, reject) => {
        console.log('Promise 对象被新建了!');
        throw new Error('内部抛出异常!');
    });
}

let p = foo();
console.log('同步的代码!');

// 另外

image.png

  • 当 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('外部执行完毕!!');

image.png

  • 回调函数的优先级高于计时器(前者属于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);
})

image.png

  • 上述代码可以简写成如下 ```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('失败!!');
})

image.png