深入了解Promise

82 阅读3分钟

深入了解Promise

Event Loop理解(重点)

讲到Promise,我们自然会想到异步带来的问题,为什么会有异步这个概念呢?

这里主要是因为JavaScript 的执行环境是单线程

所谓单线程,是指 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程。

那么为了理解单线程执行过程,这里就不得不说到事件轮询(Event Loop)

console.log('hi')

setTimeout(function cb() {
  console.log('airhua')
}, 1000)

console.log('bye')

下面我们根据这段代码来看看代码执行中为什么产生了异步

  • 同步代码,会一行一行放在Call Stack执行
  • 遇到异步,会先记录起来,等待时机(定时完成,请求完成,事件函数执行时)
  • 时机到了,就移动到Callback Queue
  • 如果Call Stack为空(同步代码执行完)Event Loop开始工作
  • 轮询查找Callback Queue,如有则移动到Call Stack执行

1643641444396.png

1643641463464.png

1643641486901.png

而解决为这个异步问题有以下几个方法:

  • 回调函数
  • Promise then
  • async await(这个放在下篇写)

在很久以前写过一篇Promise then理解,感觉里面例子还是很奇怪,大家也可以先看一下这篇async await用法,或者直接看这篇,毕竟以前写的有点模糊,这里也是对前面的一个补充。

回调函数解决异步

先来看看利用回调函数解决异步问题的写法:

// 定义一个异步的延迟函数:异步函数结束1秒之后,再执行cb回调函数
function fun1(cb) {
    setTimeout(cb, 1000);
}

// 先执行异步函数fun1,再执行回调函数
fun1(function () {
    console.log('我是延迟执行的cb回调函数');
});

Promise写法

function fun2() {
    return new Promise((resolve) => {
        setTimeout(resolve, 1000);
    });
}
// 先执行异步函数fun1,再执行回调函数
fun2().then(() => {
    console.log('我是延迟执行的回调函数');
});

使用Promise手写加载一张图片

先来看看一个面试题例子理解:

function loadImg(src) {
  const p = new Promise((resolve, reject) => {
    const img = document.createElement('img')
    img.onload = () => {
      resolve(img)
    }
    img.onerror = () => {
      const err = new Error('图片加载失败')
      reject(err)
    }
    img.src = src
  })
  return p
}

const url = 'https://assets.huabyte.com/blog/image/cover1.jpg'
loadImg(url).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err);
})

Promise对象的三个状态

通过以前的知识我们也可以总结出:

  • 初始化(等待中):pending
  • 成功:fulfilled
  • 失败:rejected

接下来是thencatch改变状态,两条重要的规则(下面会用到)

  • then正常返回resolved,里面有报错则返回rejected
  • catch正常返回resolved,里面有报错则返回rejected

最后看看几个小demo就明白了

第一题

Promise.resolve().then(() => {
  console.log(1)  // 1
}).catch(() => {
  console.log(2)
}).then(() => {
  console.log(3) // 3
})

第二题

Promise.resolve().then(() => { // 返回 rejected 状态的 promise
  console.log(1) // 1
  throw new Error('erro1')
}).catch(() => { // 返回 resolved 状态的 promise
  console.log(2) // 2
}).then(() => {
  console.log(3) // 3
})

第三题

Promise.resolve().then(() => { // 返回 rejected 状态的 promise
  console.log(1) // 1
  throw new Error('erro1')
}).catch(() => { // 返回 resolved 状态的 promise
  console.log(2) // 2
}).catch(() => {
  console.log(3)
})