深入了解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执行
而解决为这个异步问题有以下几个方法:
- 回调函数
- 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
接下来是then
和catch
改变状态,两条重要的规则(下面会用到)
- 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)
})