Promise-基础 - 图1

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
        • (但是一但状态变为成功或者失败,则再也不能修改其状态了),
      • [[PromiseResult]]:undefined
        • [[PromiseResult]]存放的是成功的结果或者失败的原因!
    • 实例公有属性:then / catch / finally / Symbol.toStringTag=”Promise” [原型上]

image.png

疑惑一:状态改完有什么用

  • 1)基于then可以存放两个函数 p.then(onfulfilled,onrejected)
  • 2)当我们把状态修改为fulfilled成功态,则会把onfulfilled这个函数执行,相反,我们把状态修改为rejected失败态,则会把onrejected这个函数执行…
  • 3) 并且会把[[PromiseResult]]作为实参值,传递给onfulfilled/onrejected

    疑惑二:怎么改状态

  • 1) new Promise的时候,会立即把传递进来的executor[承诺执行人]函数执行,并且会给executor传递两个实参进来

    1. 我们会用两个形参变量接收resolve/reject,并且值是两个函数
  • 2)当我们执行resolve,promise实例状态变为fulfilled成功,传递的值就是成功的结果,赋值给[[PromiseResult]];

    1. 同理,只要把reject执行,promise实例状态变为rejected失败,传递的值就是失败的原因!
  • 3) 如果executor函数执行报错了,则实例的状态也是rejected失败,失败原因是就是错误信息!

    new Promise产生的实例,他的状态是成功还是失败,取决于“resolve/reject执行 或者 executor执行是否报错”

    1. //========================>基础语法
    2. let p=new Promise(function exector(resolve,reject){
    3. console.log(1);//先输出1
    4. resolve('OK');//promise实例状态变为fulfilled
    5. });
    6. console.log(p);
    7. //p.then(onfulfilled,onrejected)
    8. p.then(function onfulfilled(result){
    9. //当状态为fulfilled的时候 会执行此函数
    10. //result 存放的是成功结果 OK
    11. },function onrejected(reason){
    12. //当状态为rejected的时候,会执行此函数
    13. //reason 失败的原因
    14. });

    基于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}`); });
<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}`);
});

image.png

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'
})

原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到。