美文网首页
面试题【Day05】

面试题【Day05】

作者: 小王子__ | 来源:发表于2021-08-30 18:32 被阅读0次

本篇绪论

  • 1,promise
  • 2,async/await
1,promise

promise是异步编程的一种解决方案,其实就是一个构造函数。有all、reject、resolve方法,原型上有then、catch方法。

promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

const fun =() => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log(1)
        resolve(' resolved ')
      }, 2000)
    })
  }

执行fun函数我们得到了一个Promise对象,我们可以用Promise对象上的then、catch方法

fun().then(res => {
    console.log(res)
  })

promise的优势在于,在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。Promise能够简化层层回调的写法,而实质上,promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,使用promise的正确场景是:

fun()
.then(res => {
  console.log(res)
  return fun1()
})
.then(res => {
  console.log(res)
  return fun2()
})
.then(res => {
  console.log(res)
})

这样能够按顺序输出每个异步回调中的内容。

resolve是对promise的成功回调,它把promise的状态修改为fulfilled;reject是对promise的失败时候的回调,它把promise的状态修改为rejected,这样我们在then中就能捕获到结果。

const fun =() => {
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        let num = Math.ceil(Math.random() * 20)
        console.log('随机数:', num)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('数字大于10了,将执行失败回调')
        }
      },1000)
    })
  }
  fun()
  .then(res => {
    console.log('resolved成功回调')
    console.log('resolved成功回调的值:', res)
  }, err => {
    console.log('rejected失败回调')
    console.log('失败回调抛出的失败原因', err)
  })
image image
catch用法

catch是用来捕获异常的,和.then方法里接受的第二个参数rejected的回调是一样的。

const fun =() => {
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        let num = Math.ceil(Math.random() * 20)
        console.log('随机数:', num)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('数字大于10了,将执行失败回调')
        }
      },1000)
    })
  }
  fun()
  .then(res => {
    console.log('resolved成功回调')
    console.log('resolved成功回调的值:', res)
  })
  .catch((reason) => {
    console.log('catch失败回调')
    console.log('catch失败执行回调抛出失败原因:', reason)
  })
image
all

与then同级的另一个方法,all具有并行执行异步操作的能力,并且在所有异步操作执行完后并且执行结果都是成功的时候才执行回调。

const fun = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('数字大于10即将执行失败回调')
        }
      },1000)
    })
  }
  const fun1 = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('数字大于10即将执行失败回调')
        }
      }, 1000)
    })
  }
  const fun2 = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('数字大于10即将执行失败回调')
        }
      }, 1000)
    })
  }
  Promise.all([fun(), fun1(), fun2()])
  .then(res => {
    console.log(res)
  }, err => {
    console.log('失败', reason)
  })
image

all接收一个数组参数,这些方法为需要执行异步操作的所有方法,里面的值最终都返回Promise对象。all会把所有异步操作的结果放进一个数组中传给then,然后再执行then方法的成功回调将结果接收。

const p1 = [1,2,3,4,5].map(i => {
    return new Promise((resolve, reject) => {
      if (!i) {
        reject()
      } else {
        resolve(i)
      }
    })
  })
  const p2 = [6,7,8,9,10].map(i => {
    return new Promise((resolve, reject) => {
      if (!i) {
        reject()
      } else {
        resolve(i)
      }
    })
  })
  Promise.all([...p1, ...p2]).then(res => {
    console.log('res:', res)
  }).catch(reason => {
    console.log('失败', reason)
  })
image

all只有当所有的Promise都完成并返回成功,才会调用resolve,当有一个失败,都会进catch,被捕获错误,promise.all调用成功返回的结果是每个Promise单独调用成功之后返回的结果组成的数组,如果调用失败,返回的则是第一个reject的结果。

race

all是等所有的异步操作都执行完了再执行then方法,race方法谁先执行完成就先执行回调,先执行的无论是成功回调还是失败回调,其余的将不会再进入race的任何回调。

const fun = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        console.log('1s随机数字生成的值:', num)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('1s数字大于10即将执行失败回调')
        }
      },1000)
    })
  }
  const fun1 = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        console.log('2s随机数字生成的值:', num)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('2s数字大于10即将执行失败回调')
        }
      }, 2000)
    })
  }
  const fun2 = () => {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        const num = Math.ceil(Math.random() * 10)
        console.log('3s随机数字生成的值:', num)
        if (num <= 10) {
          resolve(num)
        } else {
          reject('3s数字大于10即将执行失败回调')
        }
      }, 3000)
    })
  }
  Promise.race([fun(), fun1(), fun2()])
  .then(res => {
    console.log(res)
  }, err => {
    console.log('失败', reason)
  })
image image
const p1 = [1,2,3,4,5].map(i => {
    return new Promise((resolve, reject) => {
      if (!i) {
        reject()
      } else {
        resolve(i)
      }
    })
  })
  const p2 = [6,7,8,9,10].map(i => {
    return new Promise((resolve, reject) => {
      if (!i) {
        reject()
      } else {
        resolve(i)
      }
    })
  })
  Promise.race([...p1, ...p2]).then(res => {
    console.log('res:', res)
  }).catch(reason => {
    console.log('失败', reason)
  })
image

promise.race会调用所有的promise,返回的结果则是所有promise中最先返回的结果,不关心是成功还是失败。

2,async/await

函数执行的时候,一旦遇到await就会先返回,等到异步操作结束,再接着执行函数体内后面的语句。

await + (promise命令或者原始类型的值),而async函数返回一个promise对象,可以作为await命令的参数

创建一个async()函数

async function fun() {
    return 1
  }
  console.log(fun())

async函数返回一个promise对象,可以调用then()方法添加一个回调函数

 async function fun(name) {
    return name
  }
  const foo = async function () {
    const f1 = await fun('xiaowang').then(res => {
      console.log('res:', res)
      return res
    })
    const f2 = fun('xiaoma')
    console.log('f1.toString:',f1.toString())
    console.log('f2.toString:',f2.toString())
  }
  foo()
image

验证了await命令在函数执行的时候,一旦遇到await就会先返回,等到异步操作结束,再接着执行函数体内后面的语句。

async函数内部return语句返回的值,会成为then方法回调函数的参数

async function foo() {
    return 'xiaowang'
  }
  foo().then(res => {
    console.log(res)
  })

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态,抛出的错误对象会被catch方法回调函数接收到

async function foo() {
    throw new Error('出错了')
  }
  foo().then(res => {
    console.log(res)
  })
  .catch(error => {
    console.log(error)
  })
image
async function foo() {
    throw new Error('出错了')
  }
  foo().then(
    res => console.log(res), 
    err => console.log(err)
  )

再看下没有await的例子

async function fun(name) {
    return name
  }
  const foo = async function () {
    const f1 = fun('xiaowang').then(res => {
      console.log('res:', res)
      return res
    })
    const f2 = fun('xiaoma')
    console.log('f1.toString:',f1.toString())
    console.log('f2.toString:',f2.toString())
  }
  foo()
image

await会阻塞代码。
如果函数体中有一个await语句后面的promise变为reject,那么整个async函数都会中断执行,我们希望即使前一个异步操作失败,也不要中断后面的异步操作

方法1:可以将第一个await放在try..catch里

async function fun(name) {
    try {
      await Promise.reject('出错了')
    } catch (e) {

    }
    return await Promise.resolve(111)
  }
  fun().then(res => {
    console.log(res)
  })

方法2:在await后面的promise对象后添加一个catch方法,处理前面可能出现的错误

async function fun(name) {
    await Promise.reject('出错了').catch(err => {
      console.log(err)
    })
    return await Promise.resolve('xiaowang')
  }
  fun().then(res => {
    console.log(res)
  })

如果有多个await命令,可以采用方法1,统一放在try..catch结构中

区别

1,Promise是ES6,async/await是ES7

2,async/await相对于promise来讲,写法更加优雅

3,reject状态:

1)promise错误可以通过catch来捕捉,建议尾部捕获错误,
2)async/await既可以用.then又可以用try-catch捕捉

相关文章

网友评论

      本文标题:面试题【Day05】

      本文链接:https://www.haomeiwen.com/subject/douoiltx.html