【精选】什么是Promise?前端开发人员会使用Promise简直就是如虎添翼

39 阅读6分钟

一、什么是Promise

目录

一、什么是Promise

1.Promise到底是做什么的呢?

2.什么是回调地狱。

二、Promise基本语法

三、什么情况下需要使用Promise

四、Promise三种状态

五、Promise链式调用

六、Promise的all方法调用(某一个需求需要发送两次请求)


一、什么是Promise

1.Promise到底是做什么的呢?

    Promise是异步编程的种解决方案

那什么时候我们会来处理异步事件呢?

    一种很常见的场景应该就是网络请求了。

    我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7—样将结果返回。

    所以往往我们会传入另外—个函数,在数据请求成功时,将数据通过传入的函数回调出去。

    如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦

但是,当网络请求非常复杂时,就会出现回调地狱。

2.什么是回调地狱。

我们来考虑下面的场景(有夸张的成分):

    我们需要通过一个urI从服务器加载一个数据data,data1中包含了下一个请求的url2

    我们需要通过data1取出url2,从服务器加载数据data2,data2中包含了下ー个请求的url3

    我们需要通过data2取出urI3,从服务器加载数据data3,data3中包含了下ー个请求的ur4

    发送网络请求ur4,获取最终的数据data4

上面的代有什么问题吗?

    正常情况下,不会有什么问题,可以正常运行并目获取我们想要的结果

    但是,这样的代看而且不容易维护

    我们更加期望的是一种更加优雅的方式来进行这种异步操作。

如何做呢?就是使用 Promise。——Promise可以以一种非常优雅的方式来解决这个问题。

二、Promise基本语法

1.这里,我们用个定时器来模拟异步事件:

    假设下面的data是从网络上1秒后请求的数据

    console. log就是我们的处理方式。

 

这是我们过去的处理方式,我们将它换成 Promise代码

 

这个例子会让我们感觉脱裤放屁,多此一挙

    首先,下面的 Promise代码明显比上面的代码看起来还要复杂

    其次,下面的 Promise代吗中包含的 resolve、 reject、then、catch都是些什么东西?

我们先不管第一个复杂度的问题,因为这样的一个屁大点的程序根本看不出来 Promise真正的作用.

2.上代码

<script>
     // new Promise时有两个参数,resolve, reject,这两个参数同时又是函数
     new Promise((resolve, reject) => {
          // 1.第一次网络请求
          setTimeout(function() {
              // 一秒后会执行
              console.log('time out')
              resolve('Hello world') // 调用resolve之后,会调用下面的then
                            //失败时调用reject
              // reject('Error data')
          }, 1000)
     }).then(data => {
          // 2.第一次拿到结果
          console.log(data)
          return new Promise((resolve, reject) => {
              // 3.第二次网络请求
              setTimeout(function() {
                   // 一秒后会执行
                   console.log('time out2')
                   resolve('Hello world2') // 调用resolve之后,会调用下面的then
                    reject('Error data2')
              }, 1000)
          }).then(data => {
              // 4.第二次拿到结果处理
              console.log(data)
          }).catch(error => {
              console.log(error)
          })
          //如果还有处理,可以继续return new Promise
     }).catch(error => {
          console.log(error)
     })

     // new Promise是异步处理,不影响后面的逻辑
     console.log('最后的')
</script>

3.另外一种写法

<script>
     // new Promise时有两个参数,resolve, reject,这两个参数同时又是函数
     new Promise((resolve, reject) => {
          // 1.第一次网络请求
          setTimeout(function() {
              // 一秒后会执行
              console.log('time out')
              resolve('Hello world') // 调用resolve之后,会调用下面的then
               reject('Error data')
          }, 1000)
     }).then(data => {
          // 2.第一次拿到结果
          // 只写一个then,可以传入两个函数,一个resolve执行,一个reject执行
          console.log(data)
     }, error => {
          console.log(error)
     })
     
</script>

三、什么情况下需要使用Promise

在进行 异步请求时,使用Promise对这个异步操作进行封装。

在处理完结果之后,使用resolve方法就会调用promise后面的then方法;报错之后,reject会调用catch方法。

在执行传入的回调函数时,会传入两个参数,resolve、reject,本身又是函数

四、Promise三种状态

首先,当我们开发中有异步操作时,就可以给异步操作包装一个Promise。异步操作之后会有三种状态:

    pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。

    fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调then()

    reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调catch()

   

五、Promise链式调用

 

1.链式调用
     new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve('aaa')
          }, 1000)
     }).then(res => {
          //1.自己处理10行代码
          console.log(res, '第一层的10行处理代码')
          // 2.对结果进行第一次处理,可以只用resolve
          return new Promise((resolve) => {
              resolve(res + '111')
          })
     }).then(res => {
          console.log(res, '第二层的10行处理代码')
          return new Promise((resolve) => {
              resolve(res + '222')
          })
     }).then(res => {
          console.log(res, '第三层的10行处理代码')
     })
     
//   aaa 第一层的10行处理代码
//   aaa111 第二层的10行处理代码
//   aaa111222 第三层的10行处理代码

2.简化链式
     new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve('aaa')
          }, 1000)
     }).then(res => {
          //1.自己处理10行代码
          console.log(res, '第一层的10行处理代码')
          // 2.对结果进行第一次处理,可以只用resolve
          return Promise.resolve(res + '111')
     }).then(res => {
          console.log(res, '第二层的10行处理代码')
          return Promise.resolve(res + '222')
     }).then(res => {
          console.log(res, '第三层的10行处理代码')
     })
     
//   aaa 第一层的10行处理代码
//   aaa111 第二层的10行处理代码
//   aaa111222 第三层的10行处理代码

3.极度简化
     new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve('aaa')
          }, 1000)
     }).then(res => {
          //1.自己处理10行代码
          console.log(res, '第一层的10行处理代码')
          // 2.对结果进行第一次处理,可以只用resolve
          return res + '111'
     }).then(res => {
          console.log(res, '第二层的10行处理代码')
          return res + '222'
     }).then(res => {
          console.log(res, '第三层的10行处理代码')
     })
     
//   aaa 第一层的10行处理代码
//   aaa111 第二层的10行处理代码
//   aaa111222 第三层的10行处理代码

4.reject的简写
     new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve('aaa')
          }, 1000)
     }).then(res => {
          //1.自己处理10行代码
          console.log(res, '第一层的10行处理代码')
          // 2.对结果进行第一次处理,可以只用resolve
          return Promise.reject(res + '111')
          //throw 'errormsg' // 手动抛出异常也可以
     }).then(res => {
          console.log(res, '第二层的10行处理代码')
          return Promise.resolve(res + '222')
     }).then(res => {
          console.log(res, '第三层的10行处理代码')
     }).catch(err => {
          console.log(err, 'err')
     })
     
     //aaa 第一层的10行处理代码
     //aaa111 err

六、Promise的all方法调用(某一个需求需要发送两次请求)

     Promise.all([
          new Promise((resolve, reject) => {
              // 1.第一次请求
              setTimeout(() => {
                   resolve('aaa1')
              }, 1000)
          }),
          new Promise((resolve, reject) => {
              // 2.第二次请求
              setTimeout(() => {
                   resolve('aaa2')
              }, 2000)
          })
     ]).then(results => {
          // 每个数组对应每个Promise,只有所有的Promise都执行完毕之后,才会调用then方法
          console.log(results[0])
          console.log(results[1])
     })