谈谈对Promise的理解

文接上回,我们来讲讲Promise,在讲Promise之前,我们先来讲另一个概念,同步和异步。

同步的特点:

  • 通常情况代码都是自上向下一行一行执行的

  • 前边的代码不执行后边的代码也不会执行

  • 同步的代码执行会出现阻塞的情况

  • 一行代码执行慢会影响到整个程序的执行

       为了解决这个问题,我们引入了一个新概念:异步,显著特点就是 一段代码的执行不会影响到其他的程序。但是又遇到了异步的问题:异步的代码无法通过return来设置返回值

异步的特点:

  1. 不会阻塞其他代码的执行

  2. 需要通过回调函数来返回结果

基于回调函数的异步带来的问题:

  1. 代码的可读性差

  2. 可调试性差

       但是呢,当我们进行一些复杂的调用的时,会出现“回调地狱”,而Promise可以帮助我们解决异步中的回调函数的问题,Promise就是一个用来存储数据的容器

       Promise是一个可以用来存储数据的对象,它存储数据的方式比较特殊,这种特殊方式使得它可以用来存储异步调用的数据。

一、Promise

1.Promise的状态

接下来讲讲Promise的状态:

  • pending   (进行中)

  • fulfilled(完成) 通过resolve存储数据时

  • rejected(拒绝,出错了) 出错了或通过reject存储数据时

注意:一个 Promise的状态 只能从 Pending 转变为 FulfilledRejected,且一旦确定状态,状态不会改变。

const myPromise = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
        const success = true; // 假设这是异步操作的结果
        if (success) {
            resolve("操作成功"); // 将 Promise 状态改为 Fulfilled,并传入值
        } else {
            reject("操作失败"); // 将 Promise 状态改为 Rejected,并传入错误信息
        }
    }, 1000);
});

2.处理 Promise的方法

Promise 提供了 .then().catch() 方法来处理异步操作的结果:

  • .then():用于处理 Promise 成功的结果。它接收两个参数:

    • 第一个参数是 Promise 成功时的回调函数。

    • 第二个参数是可选的,用于处理 Promise 失败时的回调函数。

  • .catch()专门用于处理 Promise 失败的情况。它接收一个回调函数,用于处理错误。

  • .finally()无论是正常存储数据,还是出现异常,finally总会执行。

myPromise
    .then((result) => {
        console.log("成功:", result); // 输出:成功:操作成功
    }, (error) => {
        console.log("失败:", error);
    })
    .catch((error) => {
        console.log("捕获错误:", error);
    });
    .finally(()=>{
    console.log("无论如何都输出")
})

         当我们通过then读取数据时,相当于为Promise设置了回调函数,如果PromiseState变为fulfilled,则调用then的第一个回调函数来返回数据,如果PromiseState变为rejected,则调用then的第二个回调函数来返回数据。

3.Promise 的常见方法

(1)Promise.all()

Promise.all() 同时返回多个Promise的执行结果,其中有一个报错,就返回错误

const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => resolve(3), 1000);
});

Promise.all([promise1, promise2, promise3])
    .then((results) => {
        console.log(results); // 输出:[1, 2, 3]
    })
    .catch((error) => {
        console.log("捕获错误:", error);
    });
(2)Promise.race()

返回执行最快的Promise(不考虑对错)

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve("第一个完成"), 1000);
});
const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => reject("第二个失败"), 500);
});

Promise.race([promise1, promise2])
    .then((result) => {
        console.log("成功:", result);
    })
    .catch((error) => {
        console.log("捕获错误:", error); // 输出:捕获错误:第二个失败
    });
(3)Promise.resolve()

创建一个立即完成的Promise

const value = "直接值";
const resolvedPromise = Promise.resolve(value);

resolvedPromise
    .then((result) => {
        console.log(result); // 输出:直接值
    });
(4) Promise.reject()

创建一个立即拒绝的Promise

const rejectedPromise = Promise.reject("出错了");

rejectedPromise
    .catch((error) => {
        console.log("捕获错误:", error); // 输出:捕获错误:出错了
    });
(5)Promise.any()

返回执行最快的完成的Promise 

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => reject("Promise 1 失败"), 1000);
});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => resolve("Promise 2 成功"), 2000);
});

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => reject("Promise 3 失败"), 1500);
});

Promise.any([promise1, promise2, promise3])
    .then((result) => {
        console.log("第一个成功的结果:", result); // 输出:第一个成功的结果: Promise 2 成功
    })
    .catch((error) => {
        console.log("所有 Promise 都失败了:", error);
    });

接下来我们继续深挖,Promise在代码中的执行顺序是怎样的呢?

二、宏任务和微任务

在JS中任务队列有两种,这里我们就谈到了宏任务和微任务:

宏任务 是那些在事件循环的每一“轮”中执行的任务。它们通常需要等待更长的时间才能执行,因为它们会被放入到事件循环的“宏任务队列”中。

常见的宏任务有:

  • setTimeoutsetInterval:这些函数会在指定的延迟时间后执行回调函数。

  • setImmediate(仅在 Node.js 中可用):在当前事件循环结束后的下一次事件循环中执行回调。

微任务 是那些在当前任务执行完成后,但在事件循环进入下一轮之前执行的任务。它们会被放入到“微任务队列”中,并且会在当前任务执行完成后立即执行。常见的微任务包括:

  • Promise 的回调Promise.then().catch().finally() 方法中的回调函数。

  • queueMicrotask():这是一个专门用于将任务放入微任务队列的函数。

那么宏任务和微任务的执行顺序是怎样的呢?

没错,就是事件循环机制:

  1. 执行同步代码

    • 事件循环从宏任务队列中取出一个任务执行。

    • 在执行过程中,可能会遇到微任务(如 Promise 的回调),这些微任务会被放入微任务队列。

  2. 执行微任务队列中的任务

    • 当当前宏任务执行完成后,事件循环会立即执行微任务队列中的所有任务,直到微任务队列为空。

    • 微任务的执行顺序是先进先出(FIFO)。

  3. 进入下一轮事件循环

    • 当微任务队列为空时,事件循环进入下一轮,从宏任务队列中取出下一个任务执行。

    • 如果宏任务队列为空,事件循环会等待新的宏任务进入队列。

举个栗子:

console.log("1");

setTimeout(() => {
    console.log("2");
    Promise.resolve().then(() => {
        console.log("3");
    });
}, 0);

Promise.resolve().then(() => {
    console.log("4");
});

console.log("5");

以下是解释

  1. 执行同步代码,打印 1

  2. setTimeout 的回调放入宏任务队列。

  3. Promise 的回调放入微任务队列。

  4. 执行同步代码,打印 5

  5. 当当前执行栈为空时,事件循环执行微任务队列中的任务,打印 4

  6. 微任务队列为空,事件循环进入下一轮,从宏任务队列中取出 setTimeout 的回调并执行,打印 2

  7. setTimeout 的回调执行过程中,又将一个 Promise 的回调放入微任务队列。

  8. setTimeout 的回调执行完成后,事件循环执行微任务队列中的任务,打印 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值