Promise从入门到入坑

本文详细介绍了JavaScript中的Promise,包括其作为异步编程解决方案的角色、构造函数的使用、状态转换以及错误捕获。在链式调用中,推荐使用catch捕获异常。同时,探讨了事件循环中的Promise执行顺序,通过一个面试题展示了微任务和宏任务的执行顺序。
摘要由CSDN通过智能技术生成

前言

随着JavaScript的发展,对异步操作的代码变的越来越简单。由起初的回调函数,到ES6新增的Promise,且支持链式调用解决回调地狱的问题,到现在大家耳熟能详的回调地狱的终极解决方法asyncawait


这篇只详细介绍一下Promise吧!!!

一、promise入门

抽象表达:

Promise是JS进行异步编程的新的解决方案

具体表达:

从语法上来说:Promise是一个构造函数
从功能上来说:Promise用来封装一个异步操作并且可以获取

使用:

Promise接受一个函数作为参数,该函数的两个参数分别是resolvereject,这两个参数都是回调函数,并且返回一个新的Promise对象。新的Promise对象的执行结果状态由resolvereject,决定。如果返回的是resolve,新的Promise变为resolvevalue为返回的值;如果返回的是reject,新的Promise变为rejectreason为抛出的异常。通过添加.then()去接收新的Promise对象的状态结果。

  // 成功的Promise
    const p1 = new Promise(((resolve, reject) => {
        resolve('我是成功的Promise值')
    }))

    p1.then(value=>{
        console.log(value)   // 输出 '我是成功的Promise值'
    },reason => {
        console.log(reason)
    })

    // 失败的Promise
    const p2 = new Promise(((resolve, reject) => {
        reject('我是失败的Promise值')
    }))

    p2.then(value=>{
        console.log(value)
    },reason => {
        console.log(reason)// 输出 '我是失败的Promise值'
    })

状态:

Promise对象有三种状态:pending(初始化状态)、fulfilled(成功的状态)、reject(失败的状态)
状态只能从 pending => fulfilled 或 pending => reject
状态一旦确定就不能在改变了

二、Promise入坑

1.Promise的错误捕获

// reject捕获
const p2 = new Promise(((resolve, reject) => {
        reject('我是失败的Promise值')
}))
p2.then(value=>{
    console.log(value)
},reason => {
    console.log(reason) // 输出 '我是失败的Promise值'
})

// catch捕获
const p2 = new Promise(((resolve, reject) => {
        reject('我是失败的Promise值')
}))
p2.then(value=>{
    console.log(value)
}).catch(reason=>{
    console.log(reason) // 输出 '我是失败的Promise值'
})

从上面代码可以看出reject回调和catch都可以捕获错误,没有出现链式调用的时候都可以很完美的捕获抛出异常,但是如果是链式调用的Promise应该使用哪个呢?我们正常写代码逻辑应该就是捕获到异常就抛出异常并让代码停止,不再继续向下执行了。我们来测试一下

// 还是上面那个失败的案例,我们只调用then两次,结果一样。
// reject捕获
const p2 = new Promise(((resolve, reject) => {
   reject('我是失败的Promise值')
}))

p2.then(
    value=>{
        console.log('我是value' + value)
    },reason=>{
        console.log('我是reason' + reason)
    }
).then(
    value1=>{
        console.log('我是value1' + value1)
    },reason1=>{
        console.log('我是reason1' + reason1)
    }
)
结果输出:
我是reason:我是失败的Promise值
我是value1:undefined

// catch捕获
const p2 = new Promise(((resolve, reject) => {
 reject('我是失败的Promise值')
}))

p2.then(
    value=>{
        console.log('我是value:' + value)
    }
).then(
    value1=>{
        console.log('我是value1:' + value1)
    }
).catch(reason=>{
    console.log('出错了:' + reason)
})
结果输出:
出错了:我是失败的Promise值

不知道和大家想的结果是否一致:Promise官方规定,如果一个错误在reject中被捕获处理了,那么Promise的状态将恢复过来,
这就意味着下一个then方法将接收到一个成功的Promise,这样看来结果就是对的了吧。所以当我们链式调用的时候使用catch
来捕获异常还是比较合理的!(但是catch要放在then的最后,不然catch下面的then方法还是会执行,且返回一个成功的回调。不过这似乎不台符合我们的编码习惯,哈哈)

2.事件循环中的Promise

简单介绍一下事件循环:

当同步代码执行完成后,就会开启事件循环(EventLoop),不断去循环回调队列,看队列中是否有回调函数需要被执行。若队列中有回调函数需要执行,且当前调用栈为空,则将该回调函数推入到调用栈并执行;若调用过程中发现回调函数中有内嵌的回调函数,则继续将回调函数丢入回调队列中,等当前的回调调用完成后,再开启新一轮的回调函数调用。

事件循环中的三个队列:调用栈、微任务队列、宏任务队列
调用栈: 存放并执行同步代码
微任务队列: 存放微任务的队列(Promise、async和await、nextTick…)
宏任务队列: 存放宏任务的队列(定时器、fetch…)
执行顺序: 同步代码 > 微任务 > 宏任务
下面的实例是个大厂的面试题:上就上最难的

// 下面代码的输出顺序是什么?
async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
}

async function async2() {
    console.log("async2");
}

console.log("script start");

setTimeout(function() {
    console.log("setTimeout");
}, 0);

async1();

new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});
console.log('script end')

结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

不知道大家感觉怎么样,说实话这道题在Promise相关的题中并不算太难,大家好好分析下。
有个比较希望大家注意的点:nextTick函数返回的也是一个Promise对象,也会被放入微任务队列,但是它总是比Promise对象返回的微任务先执行,这个问题先留给大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值