如何给前端小白介绍Promise

201 阅读6分钟

啥是Promise

官方解释

Promise 是异步编程的一种解决方案: 从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。 promise有三种状态:pending(等待态),fulfiled(成功态),rejected(失败态) ;状态一旦改变,就不会再变。创造promise实例后,它会立即执行。

听不懂对不对!

通俗解释

就是你给你暗恋女神发信息告白(创建了一个Promise),接着你就等她回信息了(进入pending状态),等她回信息的过程你很焦虑啊,为了缓解焦虑你去超时捏泡面(异步的操作),最后女神给你回信息了,有两种情况:一、女神答应你啦(fulfiled成功态)二、女神狠狠的拒绝你了(rejected失败态)。但是不管啥情况都没办法再改变女神的决定,这就是Promise!

好啦,解释完Promise那我们来说说Promise能干啥。

能干啥?先说答案!解决地狱回调

哦哦哦~原来Promise是用来解决地狱回调啊,那。。。啥是地狱回调?

比如:我周六想去打篮球,但是我能不能去取决于女朋友约不约我逛街,但是我女朋友约不约我逛街又取决于她闺蜜找不找她,那么我们写成代码应该这样写

function func(res, callback) {
  if (res) {
    callback()
  } else {
    console.log('兄弟们,我不能去打球了')
  }
}

let playBasketball = function () {
  // 闺蜜不找女朋友逛街了
  func(true, function () {
    // 女朋友决定找我逛街了
    func(true, function () {
      // 我要打电话给兄弟们说我不能去打球了
      func(false)
    })
  })
}

playBasketball()

这种层层嵌套的代码就叫地狱回调,代码耦合性强,一旦一个环节出错就会原地爆炸

那么用Promise怎么来写呢

let func = function (res) {
  return new Promise((resolve, reject) => {
    if (res) {
      resolve()
    } else {
      reject('兄弟们,我不能去打球了')
    }
  })
}

func(true)
  // 闺蜜不找女朋友逛街了
  .then(() => {
    return func(true)
  })
  // 女朋友决定找我逛街了
  .then(() => {
    return func(false)
  })
  // 我要打电话给兄弟们说我不能去打球了
  .catch((err) => {
    console.log(err)
  })

是不是清楚多了!就算其中一步错了也很好修改和维护。

基本用法

介绍完什么是Promise和Promise为了解决什么问题,那么接下来说一说Promise的基本用法

首先Promise是个构造函数,如果你要用,那你就new一个

从上面的例子中可以看到Promise构造函数中包含resolve和reject两个参数

  • resolve :异步操作执行成功后的回调函数
  • reject:异步操作执行失败后的回调函数

那么我们来通俗解释一下。回到刚开始我们跟女神表白的例子。

如果女神答应我了就执行resolve,如果女神拒绝我了就执行reject。懂了么?票们!

.then方法

Promise会有个.then的方法,这也是Promise的核心,.then返回的是一个新的Promise,因此可以使用链式写法,就像上面的那段代码一样,如果你想,可以一直.then下去。

.then方法可以接收两个回调函数作为参数

第一个回调函数是Promise决议为成功时执行的,第二个回调函数是Promise决议为失败时执行的。啥意思?上代码!

let love = function (msg) {
  return new Promise((resolve, reject) => {
    if (msg) {
      // 如果女神答应我,我就去跟她约会
      resolve('我们约会吧')
    } else {
      // 如果女神拒绝我,我就去超市捏泡面
      reject('去超市捏泡面')
    }
  })
}

love(true).then(res => {
  console.log(res)
}, err => {
  console.log(err)
})

如上,因为传值是true,所以打印出的是‘我们约会吧’,如果传值是false,相应打印出的就是‘去超市捏泡面’

.catch方法

这个方法就好理解了,名如其名,就是用来捕获错误的。就是说如果Promise决议为失败了,但是.then又没有处理那么就会被.catch捕获,又因为.then也返回Promise所以.then中的错误也会被.catch捕获。

所以一般我们最后都会加上.catch方法。画个小重点,.catch一样返回Promise,所以一样可以接着调用.then

.finally方法

兄弟们,咱就是这么说吧,如果.then和.catch你搞懂了,这个finally对你来说简直不在话下。

啥意思呢,还是名如其名,就是不管.then和.catch执行多少次,那么最后都得来执行下.finally。所以.finally一定是放在最后的。

你要问我有啥用?我来给你举个栗子

业务场景中经常有发送请求弹出loading等待的提示,但是有的请求是成功的,有的是失败的,咱不能在.then和.catch都加个关闭loading的操作吧,这么low的操作也不像咱们的风格,那.finally就排上用场了。

话不多说,上才艺

let func = function (msg) {
  return new Promise((resolve, reject) => {
    window.setTimeout(() => {
      if (msg) {
        resolve('成功')
      } else {
        reject('失败')
      }
    }, 1000)
  })
}

func(true)
  .then(res => {
    console.log(res)
  })
  .catch(err => {
    console.log(err)
  })
  .finally(() => {
    console.log('关闭loading')
  })

可以看到不管是成功还是失败最终都打印出了‘关闭loading’。

.all方法

.all方法就是把多个Promise组合成一个新的Promise实例。所以它接收的参数就是一个数组。返回的是一个新的Promise。

Promise.all方法必须要传入的Promise都变为fulfilled的时候它才会为fulfilled,只要有一个为rejected的时候它就变为rejected。一家人要整整齐齐的么

let Promise1 = new Promise((resolve, reject)=>{})
let Promise2 = new Promise((resolve, reject)=>{})
let Promise3 = new Promise((resolve, reject)=>{})

let p = Promise.all([Promise1, Promise2, Promise3])

p.then(funciton(){
  // 三个都成功则成功  
}, function(){
  // 只要有失败,则失败 
})

当有多个异步请求的时候咱们就可以用Promise.all来等待所有异步请求都结束后再执行操作。

.race方法

咱们再来说说这个用的很少的东东race。这个跟.all很像,也是接收多个Promise作为参数,也是返回一个新的Promise,区别在哪呢?咱们谷歌翻译一下race有竞赛的意思,也就是说传入的参数中,哪个最先改变状态,那.race就会跟着改变。也就是说谁跑的快听谁的。

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('我是小明')
  }, 1000)
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('我是小黄')
  }, 500)
})
let p3 = Promise.resolve('我是小毛')

let result = Promise.race([p1, p2, p3])

// 状态就是fulfilled,并且值就是‘我是小毛’
console.log(result)

好啦,Promise大概就是这么多东西,相信不是太难理解,大家加油哦!