乐趣区

关于javascript:总结我做的Promise题

前言

对于 Promise 的解说文章切实太多了,在此我就不写解说了,间接实战检测本人对 Promise 的了解,上面是我做过的泛滥 Promise 题外面挑出来的 13 道题,我感觉容易错或者值得讲究知识点的题,如果你想考查本人对 Promise 的把握水平,能够做做看。

这些题是我从上面两个链接的题目又选出来的,仅作为本人的错题集 / 笔记题来记录,不便当前我本人测验回顾。如果你想更全面学,倡议间接去做上面两篇的题。

特地鸣谢

  • 【倡议星星】要就来 45 道 Promise 面试题一次爽到底(1.1w 字用心整顿)
  • 八段代码彻底把握 Promise

题目 1

const promise1 = new Promise((resolve, reject) => {console.log('promise1')
  resolve('resolve1')
})
const promise2 = promise1.then(res => {console.log(res)
})
console.log('1', promise1)
console.log('2', promise2)

剖析:

  • 先遇到new Promise,执行该构造函数中的代码输入 promise1
  • 遇到 resolve 函数, 将 promise1 的状态扭转为fulfilled, 并将后果保留下来
  • 碰到 promise1.then 这个微工作,返回的是 Promisepending状态,将它放入微工作队列
  • promise2 是一个新的状态为 pendingPromise
  • 继续执行同步代码输入 promise1 的状态是 fulfilled,输入promise2 的状态是pending
  • 宏工作执行结束,查找微工作队列,发现 promise1.then 这个微工作且状态为fulfilled,执行它。

输入后果:

promise1
1 Promise{<fulfilled>: 'resolve1'}
2 Promise{<pending>}
resolve1

题目 2

const promise = new Promise((resolve, reject) => {console.log(1)
  setTimeout(() => {console.log('timerStart')
    resolve('success')
    console.log('timerEnd')
  }, 0)
  console.log(2)
})
promise.then(res => {console.log(res)
})
console.log(4)

剖析:

  • 执行 new Promsise,输入1setTimeout 宏工作加到宏工作队列,继续执行同步代码输入2
  • 遇到promise.then,但其状态还是 pending,这里了解为先不执行;而后输入同步代码4
  • 一轮循环过后,进入第二次宏工作,发现提早队列中有 setTimeout 定时器,执行它
  • 输入 timerStart,遇到resolve,将promise 的状态改为 fulfilled 且保留后果并将之前的 promise.then 推入微工作队列
  • 继续执行同步代码timerEnd
  • 宏工作全副执行结束,查找微工作队列,发现 promise.then 这个微工作,执行它。

输入后果:

1
2
4
timerStart
timerEnd
success

题目 3

const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)

剖析:

  • 从上至下,先执行第一个 new Promise 中的函数,碰到 setTimeout 将它退出下一个宏工作列表
  • 跳出 new Promise,碰到promise1.then 这个微工作,但其状态还是为 pending,这里了解为先不执行;故promise2 是一个新的状态为 pendingPromise
  • 执行同步代码 console.log('promise1'),输入promise1 的状态为pending
  • 执行同步代 console.log('promise2'),输入promise2 的状态为pending
  • 碰到第二个setTimeout,将其放入下一个宏工作列表
  • 第一轮宏工作执行完结,并且没有微工作须要执行,因而执行第二轮宏工作
  • 先执行第一个定时器里的内容,将 promise1 的状态改为 fulfilled 且保留后果并将之前的 promise1.then 推入微工作队列
  • 该定时器中没有其它的同步代码可执行,因而执行本轮的微工作队列,也就是 promise1.then,它抛出了一个谬误,且将promise2 的状态设置为了rejected
  • 第一个定时器执行结束,开始执行第二个定时器中的内容
  • 打印出 promise1,且此时promise1 的状态为fulfilled
  • 打印出 promise2,且此时promise2 的状态为rejected
promise1 Promise {<pending>}
promise2 Promise {<pending>}
Uncaught (in promise) Error: error!!! at <anonymous>:7:9
promise1 Promise {<fulfilled>: "success"}
promise2 Promise {<rejected>: Error: error!!! at <anonymous>:7:9}

题目 4

const promise = new Promise((resolve, reject) => {reject('error')
  resolve('success2')
})
promise
  .then(res => {console.log('then1:', res)
  })
  .then(res => {console.log('then2:', res)
  })
  .catch(err => {console.log('catch:', err)
  })
  .then(res => {console.log('then3:', res)
  })

剖析:

  • catch不论被连贯到哪里,都能捕捉下层未捕获过的谬误。
  • 因为 catch()也会返回一个 Promise,且因为这个Promise 没有返回值,所以打印进去的是undefined

输入后果:

catch:  error
then3:  undefined

题目 5

Promise.resolve()
  .then(() => {return new Error('error!!!')
  })
  .then(res => {console.log('then:', res)
  })
  .catch(err => {console.log('catch:', err)
  })

剖析:

  • Promise 中,返回任意一个非 promise 的值都会被包裹成 promise 对象,例如 return new Error('error!!!') 会被包装为return Promise.resolve(new Error('error!!!'))
  • .then或者 .catchreturn 一个 error 对象并不会抛出谬误,所以不会被后续的 .catch 捕捉。

当然如果你抛出一个谬误的话,能够用上面任意一种:

return Promise.reject(new Error('error!!!'))
// or
throw new Error('error!!!')

输入后果:

then:  Error: error!!!

题目 6

const promise = Promise.resolve().then(() => {return promise})
promise.catch(console.err)

剖析:

  • .then.catch 返回的值不能是 promise 自身,否则会造成死循环。

输入后果:

Promise {<rejected>: TypeError: Chaining cycle detected for promise #<Promise>}

题目 7

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)

剖析:

  • .then 或者 .catch 的参数冀望是函数,传入非函数则会产生值透传。
  • 第一个 then 和第二个 then 中传入的都不是函数,一个是数字类型,一个是对象类型,因而产生了透传,将 resolve(1) 的值间接传到最初一个then 里。

输入后果:

1

题目 8

Promise.reject('err!!!')
  .then(
    res => {console.log('success', res)
    },
    err => {console.log('error', err)
    }
  )
  .catch(err => {console.log('catch', err)
  })

剖析:

  • .then函数的第一个参数是用来解决 Promise 胜利的函数,第二个则是解决失败的函数。
  • Promise.resolve('err!!!')的值会进入胜利的函数,Promise.reject('err!!!')的值会进入失败的函数。
  • 如果去掉第二个参数,就会进入 catch()

输入后果:

'error' 'error!!!'

题目 9

Promise.resolve('1')
  .then(res => {console.log(res)
  })
  .finally(() => {console.log('finally')
  })
Promise.resolve('2')
  .finally(() => {console.log('finally2')
    return '我是 finally2 返回的值'
  })
  .then(res => {console.log('finally2 前面的 then 函数', res)
  })

剖析:

  • .finally()办法不论 Promise 对象最初的状态如何都会执行
  • 它最终返回的默认会是一个上一次的 Promise 对象值,不过如果抛出的是一个异样则返回异样的 Promise 对象。
  • 第一行代码遇到 Promise.resolve('1'), 再把.then() 退出微工作,这时候要留神,代码并不会接着往链式调用的上面走,也就是不会先将 .finally 退出微工作列表,那是因为 .then 自身就是一个微工作,它链式前面的内容必须得等以后这个微工作执行完才会执行,因而这里咱们先不论.finally()
  • 执行 Promise.resolve('2'),把.finally 退出微工作队列,且链式调用前面的内容得等该工作执行完后才执行
  • 本轮宏工作执行完,执行微工作列表第一个微工作输入1,遇到.finally(),将它退出微工作列表(第三个)待执行;再执行第二个微工作输入finally2,遇到.then,把它退出到微工作(第四个)列表待执行
  • 本轮执行完两个微工作后,检索微工作列表发现还有两个微工作,故执行,输入 finallyfinally2 前面的 then 函数 2

输入后果:

1
finally2
finally
finally2 前面的 then 函数 2

题目 10

async function async1() {console.log('async1 start')
  await new Promise(resolve => {console.log('promise1')
  })
  console.log('async1 success')
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')

剖析:

  • async1await前面的 Promise 是没有返回值的,也就是它的初始状态是 pending 状态,因而相当于始终在await
  • 所以在 await 之后的内容是不会执行的,也包含 async1 前面的.then

输入后果:

srcipt start
async1 start
promise1
srcipt end

题目 11

async function async1() {await async2()
  console.log('async1')
  return 'async1 success'
}
async function async2() {return new Promise((resolve, reject) => {console.log('async2')
    reject('error')
  })
}
async1().then(res => console.log(res))

剖析:

  • await前面跟着的是一个状态为 rejectedpromise
  • 如果在 async 函数中抛出了谬误,则终止谬误后果,不会持续向下执行。

输入后果:

async2
Uncaught (in promise) error

题目 12

var p1 = new Promise(function (resolve, reject) {foo.bar()
  resolve(1)
})

p1.then(function (value) {console.log('p1 then value:' + value)
  },
  function (err) {console.log('p1 then err:' + err)
  }
).then(function (value) {console.log('p1 then then value:' + value)
  },
  function (err) {console.log('p1 then then err:' + err)
  }
)

var p2 = new Promise(function (resolve, reject) {resolve(2)
})

p2.then(function (value) {console.log('p2 then value:' + value)
    foo.bar()},
  function (err) {console.log('p2 then err:' + err)
  }
)
  .then(function (value) {console.log('p2 then then value:' + value)
    },
    function (err) {console.log('p2 then then err:' + err)
      return 1
    }
  )
  .then(function (value) {console.log('p2 then then then value:' + value)
    },
    function (err) {console.log('p2 then then then err:' + err)
    }
  )

剖析:

Promise 中的异样由 then 参数中第二个回调函数(Promise 执行失败的回调)解决,异样信息将作为 Promise 的值。异样一旦失去解决,then 返回的后续 Promise 对象将恢复正常,并会被 Promise 执行胜利的回调函数解决。另外,须要留神 p1、p2 多级 then 的回调函数是交替执行的,这正是由 Promise then 回调的异步性决定的。

输入后果:

p1 then err: ReferenceError: foo is not defined
p2 then value: 2
p1 then then value: undefined
p2 then then err: ReferenceError: foo is not defined
p2 then then then value: 1

题目 13

var p1 = new Promise(function (resolve, reject) {resolve(Promise.resolve('resolve'))
})

var p2 = new Promise(function (resolve, reject) {resolve(Promise.reject('reject'))
})

var p3 = new Promise(function (resolve, reject) {reject(Promise.resolve('resolve'))
})

p1.then(function fulfilled(value) {console.log('fulfilled:' + value)
  },
  function rejected(err) {console.log('rejected:' + err)
  }
)

p2.then(function fulfilled(value) {console.log('fulfilled:' + value)
  },
  function rejected(err) {console.log('rejected:' + err)
  }
)

p3.then(function fulfilled(value) {console.log('fulfilled:' + value)
  },
  function rejected(err) {console.log('rejected:' + err)
  }
)

剖析:

Promise 回调函数中的第一个参数 resolve,会对 Promise 执行 ” 拆箱 ” 动作。即当 resolve 的参数是一个 Promise 对象时,resolve 会 ” 拆箱 ” 获取这个 Promise 对象的状态和值,但这个过程是异步的。p1″ 拆箱 ” 后,获取到 Promise 对象的状态是 resolved,因而 fulfilled 回调被执行;p2″ 拆箱 ” 后,获取到 Promise 对象的状态是 rejected,因而 rejected 回调被执行。但 Promise 回调函数中的第二个参数 reject 不具备”拆箱“的能力,reject 的参数会间接传递给 then 办法中的 rejected 回调。因而,即便 p3 reject 接管了一个 resolved 状态的 Promise,then 办法中被调用的仍然是 rejected,并且参数就是 reject 接管到的 Promise 对象。

输入后果:

p3 rejected: [object Promise]
p1 fulfilled: resolve
p2 rejected: reject

  • ps:集体技术博文 Github 仓库,感觉不错的话欢送 star,给我一点激励持续写作吧~
退出移动版