Promise的基本使用

Promise的基本使用

Promise是ES6推出的新特性之一,是异步编程的一种解决方案,比传统的回调函数和时间更加合理和强大。

0、回调函数

要搞明白Promise之前,我们必须要知道“回调函数”的概念。那什么是回调函数呢?

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。引用知乎 原作者:常溪玲

接下来我们通过一个案例来认识回调函数

一个回调函数的案例:

  created () {
    this.shopping(this.callbackMethodInstance, '10086', 'iPhone13')
  },
  methods: {
    callbackMethodInstance (phoneNumber, goodsName) {
      console.log(
        `号码为${phoneNumber}的用户您好,您想购买的${goodsName}到货了可以来店里取货啦`
      )
    },
    shopping (callbackMethod, phoneNumber, goodsName) {
      console.log(`${goodsName}暂时缺货,我们已经登记了号码,货到了会给您回电`)
      setTimeout(() => {
        callbackMethod(phoneNumber, goodsName)
      }, 2000)
    }
  }
}

控制台打印:

iPhone13暂时缺货,我们已经登记了号码,货到了会给您回电
// 2秒后打印
号码为10086的用户您好,您想购买的iPhone13到货了可以来店里取货啦

从上面这个案例可以看出,所谓回调函数不过是将函数作为方法传递,在一个函数内部的指定位置来执行这个函数而已。

1、Promise Quickstart

export default {
  created () {
    this.firstPromise('10086', 'iPhone13').then(data => {
      console.log(
        `号码为${data.phoneNumber}的用户您好,您想购买的${data.goodsName}到货了`
      )
    })
  },
  methods: {
    firstPromise (phoneNumber, goodsName) {
      let p = new Promise(resolve => {
        console.log(
          `${goodsName}暂时缺货,我们已经登记了号码,货到了会给您回电`
        )
        setTimeout(() => {
          resolve({ phoneNumber, goodsName })
        }, 2000)
      })
      return p
    }
  }
}

控制台打印:

iPhone13暂时缺货,我们已经登记了号码,货到了会给您回电
// 2秒后打印
号码为10086的用户您好,您想购买的iPhone13到货了可以来店里取货啦

从上面案例的结果可以看出,resolve起到了一个回调函数的作用,可以在异步操作执行结束之后返回一个结果。可以通过.then的形式来调用这个回调函数。它和回调函数的区别就是,没有将函数作为参数,使用resolve函数代替,resolve中只能有一个参数,多余的参数会被忽略。使用.then的形式来调用这个“回调函数”

.catch的用法

看到这里,如果你用过axios的话你会发现,这不就是axios中的.then.catch么?没错,axios使用了Promise进行了封装,.then我们知道是怎么回事了,那么.catch怎么用呢?

我们知道catch一般是用来捕获异常的,在Promise中通常也这么用。在Promise中管理了一个“状态”,我们前面看到的resolve是将状态设置为fullfiled,我们可以粗浅的理解它为“成功状态”。那与之对应的一定有“失败状态”对吧,reject函数是将Promise的状态设置为rejected,我们可以简单的把它理解为“失败状态”。注:这里所说的成功和失败状态不是严谨的说法,只是为了方便我们理解而已。

继续来看案例:

export default {
  created () {
    this.firstPromise('10086', 'iPhone13')
      .then(data => {
        console.log(
          `号码为${data.phoneNumber}的用户您好,您想购买的${data.goodsName}到货了`
        )
      })
      .catch(error => {
        console.log(
          `号码为${error.phoneNumber}的用户抱歉,您想购买的${error.goodsName}已经过了两个月了,仍然没有货`
        )
      })
  },
  methods: {
    firstPromise (phoneNumber, goodsName) {
      let p = new Promise((resolve, reject) => {
        console.log(
          `${goodsName}暂时缺货,我们已经登记了号码,货到了会给您回电`
        )
        setTimeout(() => {
          if (goodsName === 'iPhone12') {
            resolve({ phoneNumber, goodsName })
          } else {
            reject({ phoneNumber, goodsName })
          }
        }, 2000)
      })
      return p
    }
  }
}

控制台打印:

iPhone13暂时缺货,我们已经登记了号码,货到了会给您回电
// 2秒后打印
号码为10086的用户抱歉,您想购买的iPhone13已经过了两个月了,仍然没有货

这一次,很明显.then没有执行,.catch执行了。这是因为firstPromise中执行了reject,状态修改为了rejected。此时只有.catch会被执行。

Promise的三种状态

  • pending-进行中
  • fulfilled-成功
  • rejected-失败

Promise对象,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,但Promise对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

状态的改变(或者说决议)不可逆,一旦决议就不能再更改。

任何时候都可以得到这个结果,Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型),如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果,这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

我们再来看一个案例:

export default {
  created () {
    // this.shopping(this.callbackMethodInstance, '10086', 'iPhone13')
    this.firstPromise('10086', 'iPhone13')
      .then(data => {
        console.log(
          `号码为${data.phoneNumber}的用户您好,您想购买的${data.goodsName}到货了`
        )
      })
      .catch(error => {
        console.log(
          `号码为${error.phoneNumber}的用户抱歉,您想购买的${error.goodsName}已经过了两个月了,仍然没有货`
        )
      })
  },
  methods: {
    firstPromise (phoneNumber, goodsName) {
      let p = new Promise((resolve, reject) => {
        console.log(
          `${goodsName}暂时缺货,我们已经登记了号码,货到了会给您回电`
        )
        setTimeout(() => {
          resolve({ phoneNumber, goodsName })
        }, 2000)
        reject({ phoneNumber, goodsName })
      })
      return p
    }
  }
}

控制台打印:

iPhone13暂时缺货,我们已经登记了号码,货到了会给您回电
// 立即打印
号码为10086的用户抱歉,您想购买的iPhone13已经过了两个月了,仍然没有货

这个案例不是很好,但是我们可以看出在执行了reject函数后,没有继续的等待resolve执行。这就是我们前面说的Promise状态的改变(或者说决议)不可逆,一旦决议就不能再更改。

2、回调地狱

如果只是上面这点作用,那Promise也不过如此嘛,不就是回调函数换了一种写法而已。那如果回调函数中又有一个异步操作需要回调函数,它内部还有异步操作呢?这就是我们所说的“回调地狱”。

回调地狱案例代码:

function sayNum(name, callback) {
        setTimeout(() => {
            console.log(name);
            callback()
        }, 1000)
    }
    sayNum('one', function () {
        sayNum('two', function () {
            sayNum('three', function () {
                sayNum('four', function () {
                    console.log('结束了');
                })
            })
        })
    })
//打印结果 one two three four 结束了

Promise链式操作

Promise是避免回调地狱的一个进步,通过.then( )的链式操作来触发多个异步任务,并且保证执行顺序,使得代码更易于阅读和维护。

怎么样,经过Promise化后,代码是不是看起来清晰多了。

function fn(num) {
        return new Promise(function (resolve, reject) {
            setTimeout(() => {
                console.log(num);
                resolve(num)
            }, 1000)
        })
    }
    
    var p1 = fn('one')
    p1.then((data) => {
            return fn('two')
        })
        .then((data) => {
            return fn('three')
        })
        .then((data) => {
            return fn('four')
        })
//  打印结果  one two three four

3、Promise补充-两个对象方法

all的用法

Promise.all( ): 并发处理多个异步任务,所有任务都执行完成才能得到结果,并发处理的任务都是按照顺序执行的

        var p1 = fn('第一次')
        var p2 = fn('第二次')
        var p3 = fn('第三次')
        
        Promise.all([p1, p2, p3]).then((res) => {
            console.log(res);
        })
//  打印   ['第一次','第二次','第三次']

race的用法

Promise.race( ):并发处理多个异步任务,只要有一个任务完成就能得到结果

        var p1 = fn('第一次')
        var p2 = fn('第二次')
        var p3 = fn('第三次')
        
        Promise.all([p1, p2, p3]).then((res) => {
            console.log(res);
        })
//  打印   第一次

参考:

简书-飞蝗tengda 【promise-04】Promise的三种状态

知乎-常溪玲 回调函数(callback)是什么?

博客园-吕大豹 大白话讲解Promise(一)

知乎-浅谈:从回调地狱到Promise(三个实例方法,两个对象方法)

posted @ 2021-12-06 17:36  张瑞丰  阅读(188)  评论(0编辑  收藏  举报