Promiss基础入门(新手友好)

🔮 欢迎点赞 👍٩( ´︶` )( ´︶` )۶ 收藏 🌟留言 💌 欢迎讨论!💕
🔮 本文由 【第四人称Alice】 原创,首发于 优快云 ✨✨✨
🌍 由于博主还属于前期的前端开发小白,欢迎大家留言提出更好的意见,大家共同进步!💭

声明:博主的项目是vue3+ts,node版本18.18.2 

一、概述

1、含义

(1) Promise 是 ES6 引入的一种异步编程解决方案,它旨在简化复杂的异步流程,尤其是消除传统的“回调地狱”,它是立即执行函数

(2)Promise 的核心在于它代表了一个将来可能完成的异步操作,共有三种状态:pending(等待中)、fulfilled(已成功)和rejected(已失败)

此处为了便于大家理解Promiss的三种状态,举一个猜字游戏的例子:

①Pending(等待中):你心里已经想好了一个数字,等待(pending)朋友猜测;

②Fulfilled(已成功):朋友猜对了,游戏成功(fulfilled)

③Rejected(已失败):朋友猜错了,游戏失败(rejected)

通过一个实际的例子来说明这三种状态的变化:

function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    // 模拟异步操作,例如网络请求
    setTimeout(() => {
      if (typeof userId === 'string') {
        // 假设请求成功,模拟返回用户数据
        resolve({ id: userId, name: 'User ' + userId, email: userId + '@example.com' });
      } else {
        // 请求失败,参数错误
        reject(new Error('Invalid user ID'));
      }
    }, 1000); // 模拟延迟1秒后完成操作
  });
}

// 使用Promise处理异步操作
fetchUserData('123')
  .then(userData => {
    console.log('用户数据获取成功:', userData);
  })
  .catch(error => {
    console.error('获取用户数据时出错:', error.message);
  });

打印结果:

在这个例子中:

  • Pending(等待中):当fetchUserData函数被调用时,一个新的Promise实例被创建,此时Promise处于Pending状态。这是在setTimeout开始计时,但还未执行完成之前的状态。

  • Fulfilled(已成功):如果userId是一个有效的字符串,模拟的异步操作在1秒后完成,resolve函数被调用,Promise的状态变为Fulfilled。这时,我们在.then回调中处理成功的结果,打印出用户数据。

  • Rejected(已失败:如果userId不是一个字符串,模拟的错误情况发生,reject函数被调用,Promise的状态变为Rejected。这时,错误处理逻辑在.catch回调中执行,打印出错误信息。

(3)Promiss是一个构造函数,它用于创建Promise实例,这个构造函数接受一个执行器函数(executor function)作为参数,这个执行器函数接收两个参数resolvereject,它们分别是用于改变Promise状态的函数。

 注意:看到有人会把已经完成的状态说成 resolved,查阅了官方资料后终于有了解释,严格意义上是使用 pendingfulfilledrejected 这三个术语。 resolved 这个词在日常交流中有时会被用来泛指Promisepending状态转变到fulfilled状态的过程,但它并不是Promise规范中定义的一个独立状态。正确的表述是,当Promise从pending变为成功时,我们说它被fulfilled了,而不是说它变成了 resolved 状态。官网称resolved为“已定型”是指它意味着promiss的结果是可以依赖的,状态已固定,不会再有其他改变。

官网参考:ES6 入门教程

二、Promiss相关方法

1、实例方法

实例方法需要在创建Promiss实例后,在Promiss对象上使用

(1)Promise.prototype.then()

  • 添加成功和/或失败回调,用于处理Promise解析后的结果或错误。
  • onFulfilled是Promise解析后的回调,onRejected是Promise被拒绝时的回调。
  • 语法:promise.then(onFulfilled, onRejected)

(2)Promise.prototype.catch()

  • 处理Promise被拒绝时的错误,可以看作是.then(null, onRejected)的简写形式。
  • 语法:promise.catch(onRejected)

(3)Promise.prototype.finally()

  • 不管Promise是成功还是失败,都会执行的回调。
  • 语法:promise.finally(onFinally)

.then / .catch / .finally综合例子

// 模拟一个异步操作,可能会成功或失败
//asyncOperation函数返回一个Promise,模拟一个异步操作,2秒后随机决定成功或失败。
function asyncOperation() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 ? resolve('Operation successful') : reject(new Error('Operation failed'));
    }, 2000);
  });
}

// 创建Promise实例并开始异步操作asyncOperation
const myPromise = asyncOperation();

myPromise
  .then(result => {
//使用.then()方法添加一个成功回调,当Promise解析(fulfilled)时执行。它会打印出操作成功的消息。
    console.log('Success:', result);
  })
  .catch(error => {
//使用.catch()方法添加一个错误处理回调,当Promise被拒绝(rejected)时执行。它会打印出错误信息。
    console.error('Error:', error.message);
  })
  .finally(() => {
//使用.finally()方法添加一个最终回调,无论Promise成功还是失败,都会在操作结束后执行。
    console.log('Operation finished, cleaning up resources...');
    // 在这里可以进行一些清理工作,例如关闭数据库连接、清除定时器等

  });

2、静态方法

(1)Promise.all()

  • 接收可迭代对象Promise.all接收一个包含Promise实例的数组、Map或Set等可迭代对象。
  • 并发执行:同时执行输入的多个Promise,提高异步操作的效率。
  • 整体结果:当所有传入Promise实例都解析成功时,返回一个新的Promise解析,其结果是一个包含所有解析值的数组(全成则成)。
  • 单一失败:只需一个Promise实例被拒绝,Promise.all就会失败,不等待其他Promise实例(一败皆败)。
  • 错误处理:通过.catch统一处理首个失败Promise的错误。只需一个错误整个链路就会中断。
  • 顺序保留:结果数组的顺序与传入可迭代对象中的Promise实例顺序对应。
  • 非阻塞性:不影响代码其他部分继续执行。
  • 资源管理:结合.finally确保最终资源清理。
  • 对比Promise.racePromise.all关注所有Promise完成,Promise.race关注第一个完成的Promise

 拓展:字节飞书面试——请实现promise.all - 掘金

// 创建三个不同的数据结构

// 1、创建一个数组,其中包含Promise
const arrayPromise = [
  new Promise((resolve, reject) => setTimeout(() => resolve('Array Value 1'), 1000)),
  new Promise((resolve, reject) => setTimeout(() => resolve('Array Value 2'), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve('Array Value 3'), 3000))
];

// 2、创建一个Map,其中键是字符串,值是Promise
const mapPromise = new Map([
  ['key1', new Promise((resolve, reject) => setTimeout(() => resolve('Map Value 1'), 1500))],
  ['key2', new Promise((resolve, reject) => setTimeout(() => resolve('Map Value 2'), 2500))]
]);

// 3、创建一个Set,其中的元素是Promise
const setPromise = new Set([
  new Promise((resolve, reject) => setTimeout(() => resolve('Set Value 1'), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve('Set Value 2'), 3000))
]);

// 将Map和Set转换为可迭代对象
const mapIterable = Array.from(mapPromise.values());
const setIterable = [...setPromise];

// 将三组数据合并到一个数组
// 使用Promise.all处理所有Promise
Promise.all([...arrayPromise, ...mapIterable, ...setIterable])
  .then(values => {
    // 当所以传入Promiss成功时,打印所有成功的promiss解析值,values是一个数组
    console.log('All promises resolved:', values);
  })
  .catch(error => {
    // 任何Promise失败,这里会捕获错误
    console.error('An error occurred:', error);
  });

(2)Promise.race()

  • 并发启动:所有Promise并发执行,但只关注第一个完成的。
  • 竞争模式:监听一组Promise,返回最先完成(无论是成功还是失败)的Promise的结果。
  • 立即响应:一旦有任一Promise改变状态(解析或拒绝),返回的Promise立即跟随该状态。
  • 单个结果:结果是第一个完成的Promise的解析值或错误,忽略其他Promise。
  • 错误处理:如果第一个完成的Promise是拒绝状态,返回的Promise也会被拒绝。
  • 非阻塞性:不会阻止其他Promise继续执行,即使它们后续完成。
  • 灵活性高:适用于超时控制、竞态条件处理场景。
  • 资源管理:结合.finally处理无论成功还是失败后都需要进行的清理操作。
  • Promise.all对比:Promise.race关注速度,Promise.all关注完整性。
// 使用Promise.race处理所有Promise
Promise.race([...arrayPromise, ...mapIterable, ...setIterable])
  .then(value => {
    // 打印第一个完成的Promise的解析值
    console.log('First promise resolved:', value);
  })
  .catch(error => {
    // 如果第一个完成的Promise被拒绝,这里会捕获错误
    console.error('An error occurred:', error);
  });

(3)Promiss.any()

  • 并行执行:和Promise.all类似,Promise.any也并行执行传入的Promise
  • 等待任意一个成功:接收一个Promise实例的数组,只要数组中有一个Promise成功,就返回成功Promise。
  • 第一个成功者:一旦有一个Promise成功,其他的Promise状态如何都不会影响结果。
  • 快速响应:不等待所有Promise,一旦有一个成功,Promise.any就会立即响应。
  • 所有失败的情况:如果所有的都失败,才会返回失败状态,返回的失败原因是一个AggregateError对象。
  • 错误信息:在Aggregate中可以获取所有失败Promise的错误信息。
  • 错误处理:使用.catch来捕获Promise.any返回的Promise失败情况。
  • 非标准特性Promise.any是ES2021引入的新特性,不是所以浏览器或环境都支持。
  • 对比Promiss.allPromise.all要求所有Promise都成功,而Promise.any只要有一个成功即可。
  • 对比Promiss.racePromise.race返回第一个完成的Promise,不论成功或失败;而Promise.any只关注成功的情况。
// 使用Promise.any
Promise.any([...arrayPromise, ...mapIterable, ...setIterable])
  .then(data => {
    console.log('First successful data:', data);
  })
  .catch(error => {
    if (error instanceof AggregateError) {
      console.error('All promises failed:', error.errors);
    } else {
      console.error('An unexpected error:', error);
    }
  });

(4)Promiss.allSettled()

  • 并行处理:所有Promise是并行处理的,不依赖于彼此的完成顺序。
  • 等待所有Promise完成Promise.allSettled会等待传入的所有Promise完成(无论成功或失败)。
  • 返回详细结果:不仅关心是否成功,还关注每个Promise的最终状态,返回每个Promise的解决详情数组。
  • 状态区分:每个Promise的解决详情包括两种状态:fulfilled(已完成)或rejected(已拒绝)。
  • 包含结果或原因:对于fulfilled状态,包含实际的解析值;对于rejected状态,包含拒绝原因。
  • 非阻塞:即使某些Promise失败,也会继续等待其余Promise完成,不会立即拒绝整个操作。
  • 适用场景:适用于需要了解一组异步操作的整体结果,而不希望因单个失败而中断流程的情况。
  • ES2020特性Promise.allSettled是ES2020引入的新特性,可能在一些旧环境或浏览器中不支持。
// 使用Promise.allSettled
Promise.allSettled([...arrayPromise, ...mapIterable, ...setIterable])
    .then(results => {
    // 结果是一个数组,包含每个Promise的详细状态
    console.log('Results for all settled Promises:');
    results.forEach((result, index) => {
      // 检查每个Promise的状态
      if (result.status === 'fulfilled') {
        // 如果Promise成功,打印解析值
        console.log(`Promise ${index + 1} succeeded with value:`);
        console.log(result.value);
      } else {
        // 如果Promise失败,打印拒绝原因
        console.log(`Promise ${index + 1} failed with reason:`);
        console.log(result.reason);
      }
    });
  })
  .catch(error => {
    // 如果Promise.allSettled自身抛出错误,这里捕获
    console.error('An unexpected error occurred in Promise.allSettled:', error);
  });

总结 .all / .race / .any / .allSettled 的区别

  • Promise.all等待所有Promise成功才返回。
  • Promise.race在第一个Promise完成(无论是成功还是失败)时返回。
  • Promise.any只要有一个Promise成功就返回。
  • Promise.allSettled等待所有Promise完成,无论成功还是失败,返回每个Promise的状态详情。

(5)Promise.resolve()

  • 创建成功Promise:用来快速创建一个已经完成(fulfilled)或失败(rejected)状态的Promise实例。
  • 值转换:传入非Promiss会转为Promiss并返回
  • Promiss兼容:如果传入的是一个Promise,它会直接返回这个Promise,不创建新的。
  • 同步处理:用于将同步操作包装为Promise,方便在异步流程中使用。
  • 链式调用:创建的Promise可以与.then.catch等方法进行链式调用。
  • 错误处理:可以在链中使用.catch捕获Promise.resolve创建的Promise可能出现的错误。
  • 简化构造:相比直接使用new Promise构造函数,Promise.resolve更简洁,减少手动处理Promise状态的复杂性。
  • 异步流程整合:常用于将非Promise的异步操作转换为Promise,以便于在Promise链中处理。
// 1. 创建一个Promise实例
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise resolved'), 1000);
});

// 2. 创建一个非Promise值
const myValue = 'Non-Promise Value';

// 使用Promise.resolve分别处理Promise和非Promise
const resolvedPromise = Promise.resolve(myPromise);
const resolvedValue = Promise.resolve(myValue);

// 同时处理这两个Promise
Promise.all([resolvedPromise, resolvedValue])
  .then(results => {
    console.log('Resolved Promise:', results[0]); // 输出: "Resolved Promise: Promise resolved"
    console.log('Resolved Non-Promise:', results[1]); // 输出: "Resolved Non-Promise: Non-Promise Value"
  })
  .catch(error => {
    console.error('An error occurred:', error);
  });

// 分别处理这两个Promise 

//成功处理
resolvedPromise.then(result => {
  console.log('Resolved Promise:', result); // 输出: "Resolved Promise: Promise resolved"
});

resolvedValue.then(result => {
  console.log('Resolved Non-Promise:', result); // 输出: "Resolved Non-Promise: Non-Promise Value"
});

// 错误处理
resolvedPromise.catch(error => {
  console.error('Error in resolvedPromise:', error);
});

resolvedValue.catch(error => {
  console.error('Error in resolvedValue:', error);
});

(6)Promise.reject()

  • 创建失败PromissPromise.reject用于创建一个已拒绝(rejected)状态的Promise对象。
  • 传递原因:可以传入一个值作为拒绝的原因,通常是一个错误对象。
  • 中断流程:一旦使用Promise.reject,Promise链会立即停止,不再执行后续的.then
  • 错误处理:必须使用.catch来捕获Promise.reject创建的Promise的错误。
  • 同步或异步:无论在同步代码还是异步代码中,Promise.reject都会创建一个拒绝的Promise。
  • 链式调用:与.then一起使用时,.catch用于处理Promise.reject后的错误。
  • 非阻塞性:尽管Promise链停止,但不会阻止其他代码的执行。
  • 异常转换:有时用于将抛出的异常转换为Promise的拒绝状态,以在异步环境中处理异常。

举个例方便理解:想象一下,你在网上购物,提交了一个订单,但系统需要检查你的支付方式是否有效。如果支付方式不被接受,系统就需要告诉你订单无法完成。这里,我们可以用Promise.reject来表示这个错误情况。

function placeOrder(paymentMethod) {
  // 假设这是个异步操作,检查支付方式是否有效
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (paymentMethod === 'credit card' || paymentMethod === 'PayPal') {
        console.log('Payment method accepted, placing your order...');
        resolve(`Your order has been placed using ${paymentMethod}.`);
      } else {
        console.log('Payment method not supported.');
        reject(new Error(`Sorry, we don't accept payments via ${paymentMethod}.`));
      }
    }, 2000); // 模拟检查需要2秒
  });
}

// 用户尝试使用"Bitcoin"支付
placeOrder('Bitcoin')
  .then(orderConfirmation => {
    console.log(orderConfirmation);
  })
  .catch(error => {
    console.error('Order placement failed:', error.message);
  });

在这个例子中,placeOrder函数代表提交订单的过程,它返回一个Promise。如果传入的支付方式(paymentMethod)是“credit card”或“PayPal”,那么这个Promise会被解析(resolve),表示订单成功提交。但如果支付方式是不支持的,如“Bitcoin”,则使用Promise.reject来拒绝这个Promise,并提供一个错误原因——“我们不接受这种支付方式”。

当用户尝试使用比特币支付时,catch块会捕获到由Promise.reject抛出的错误,并打印出“Order placement failed: Sorry, we don't accept payments via Bitcoin.”,这样用户就能明白为什么订单没能成功提交。

三、Promiss的特性以及举例:

1、错误处理

        错误传播是Promise的一个重要特性,未在.then()中捕获的错误会自动传递到.catch(),简化了错误处理流程。

// 定义一个模拟的异步操作,例如从服务器获取数据
function fetchData() {
  return new Promise((resolve, reject) => {
    // 模拟网络延迟
    setTimeout(() => {
      // 模拟可能发生的错误情况,比如服务器返回错误状态
      if (Math.random() < 0.5) {
        reject(new Error('Server returned an error: Data not found'));
      } else {
        // 模拟成功获取数据
        const data = { key: 'value' };
        resolve(data);
      }
    }, 2000); // 模拟2秒的延迟
  });
}

// 使用Promise的错误处理
fetchData()
  .then((data) => {
    // 当Promise成功时,这里处理数据
    console.log('Data received:', data);
  })
  .catch((error) => {
    // 当Promise被拒绝时,这里捕获并处理错误
    console.error('An error occurred:', error.message);
    // 可能的错误处理操作,比如重试、记录日志、通知用户等
    // 在生产环境中,你可能需要更复杂的错误处理逻辑
  })
  .finally(() => {
    // 不论Promise成功还是失败,finally始终会被调用
    // 通常在这里进行资源清理、解除订阅或其他收尾工作
    console.log('Promise chain completed, cleaning up resources...');
  });

2、 链式调用

        通过 .then() .catch() 方法将多个异步操作串联起来。.then() 用于处理成功的情况,可以链式调用更多的 .then().catch() 用于捕获并处理在前面的 .then() 中抛出的错误,使得错误处理成为链式的一部分,.finally() 可以在操作完成后执行,无论成功还是失败都要执行的代码。以上第三种方法都会返回新的Promiss

// 模拟一个获取数据的异步操作
function fetchData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = { id: 1, name: 'John Doe', age: 30 };
      resolve(data);
    }, 2000); // 模拟2秒的延迟
  });
}

// 模拟处理数据的异步操作
function processData(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 对数据进行一些处理,例如过滤或转换
      const processedData = { ...data, processed: true };
      resolve(processedData);
    }, 1000); // 模拟1秒的延迟
  });
}

// 模拟将数据存储到数据库的异步操作
function storeToDatabase(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('Data stored:', data);
      resolve('Data stored successfully');
    }, 1500); // 模拟1.5秒的延迟
  });
}

// 链式调用开始
fetchData('https://api.example.com/data')
  .then(data => processData(data))
  .then(processedData => storeToDatabase(processedData))
  .then(message => console.log(message))
  .catch(error => console.error('An error occurred:', error))
  .finally(() => {
    console.log('Finally block executed, regardless of success or failure.');
    // 在这里可以进行一些清理工作,如关闭数据库连接、释放资源等
  });

在这个例子中,fetchData函数模拟了从远程API获取数据的异步操作,processData函数模拟了对数据进行处理的步骤,storeToDatabase函数则模拟了将处理后的数据存储到数据库的过程。每个函数都返回一个新的Promise,使得可以使用.then.catch来链接这些操作。如果其中一个步骤中出现错误,.catch会捕获并处理这个错误。.finally函数会在整个链式调用完成后执行,无论之前的成功或失败。在.finally回调中,你可以执行一些收尾工作,如关闭数据库连接、释放资源或显示一条消息,表明所有操作已完成。

请注意,.finally函数不会改变Promise链中的值或错误。如果你需要在.finally中返回一个值,可以使用.then来捕获这个值,但它不会影响前面的链式调用。同样,如果.finally中抛出错误,它会被下一个.catch捕获,但不会影响前面的链式调用结果。

结合注意举例:

// 假设我们有一个模拟的断开数据库连接函数
function disconnectFromDatabase() {
  return new Promise((resolve, reject) => {
    console.log('Disconnecting from database...');
    setTimeout(() => {
      console.log('Disconnected!');
      resolve('Disconnected');
    }, 1000); // 模拟1秒的断开延迟
  });
}
// 链式调用开始
fetchData('https://api.example.com/data')
  .then(data => processData(data))
  .then(processedData => storeToDatabase(processedData))
  .then(message => console.log(message))
  .catch(error => console.error('An error occurred:', error))
  .finally(() => {
    console.log('Finally block executed, regardless of success or failure.');
    return disconnectFromDatabase();
  })
  .then(disconnectMessage => console.log(disconnectMessage))
  .catch(disconnectError => console.error('Error while disconnecting:', disconnectError));;

在这个例子中,我们首先模拟了连接到数据库,然后执行查询,如果一切顺利,会输出一条消息表示查询成功。如果在任何阶段发生错误,.catch会捕获并打印错误信息。无论成功还是失败,.finally函数都会执行,模拟断开数据库连接。如果断开连接过程中发生错误,最后一个.catch会捕获并打印这个错误。

3、状态不可逆

        指Promise 一旦从 pending(等待中)状态变为 fulfilled(已成功)或从 pending(等待中)状态变为 rejected(已失败)状态,其状态就不可更改了。这意味着你不能让一个已经完成的 Promise 再次变为 pending(等待中)状态,也不能改变已完成 Promise 的结果。

let myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise fulfilled'); // 操作成功,Promise状态变为fulfilled
  }, 1000);
});

// 尝试在Promise状态改变后再次改变它,这是无效的
myPromise.then(() => {
  // 模拟尝试再次改变状态
  myPromise.status = 'pending'; // 这行代码不会改变Promise的状态
  // 或者尝试再次调用resolve或reject,这同样无效
  // resolve('Should not work!'); 
});

// 正常处理Promise
myPromise
  .then(result => {
    console.log('Promise fulfilled:', result);
  })
  .catch(error => {
    // 这个catch不会触发,因为我们已经成功调用了resolve
    console.error("Promise rejected:", error);

  });

打印结果:

在这个例子中,我们创建了一个Promise,它在1秒后通过resolve函数改变状态为fulfilled。然后,我们尝试在.then回调中再次改变Promise的状态,包括尝试设置status属性为pending,或者再次调用resolve。这些尝试都是无效的,因为Promise的状态一旦确定,就不能再改变。

在后续的.then链中,我们打印出成功的结果。由于Promise已经被成功解决,.catch部分不会执行,因为没有错误发生。这进一步证明了Promise状态的不可逆性:一旦状态被决议,后续的代码无法逆转这一决议。

注意:请注意,如果在.then.catch中抛出错误,这不会改变Promise的状态,而是会触发后续的.catch处理程序,除非显式地捕获并处理了这个错误。

结合注意点举例在.then中尝试改变promiss状态:

let myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise fulfilled');
  }, 1000);
});

// 在.then()中尝试抛出错误,但这不会改变Promise的状态
myPromise
  .then(result => {
    console.log('Promise fulfilled:', result);
    // 模拟在处理结果时出现的错误
    throw new Error('Error in processing result');
  })
  .catch(error => {
    // 这个catch会捕获并处理上面的错误,但不会改变Promise的状态
    console.error('Error caught:', error.message);
  });

// 再次尝试在后续的.then()中改变状态,这是无效的
myPromise
  .then(() => {
    // 模拟尝试再次改变状态
    myPromise.status = 'pending'; // 这行代码不会改变Promise的状态
    // 或者尝试再次调用resolve或reject,这同样无效
    // resolve('Should not work!'); 
  });

一般在.catch中抛出错误是不常见的做法,因为.catch通常用于捕获和处理之前的错误,而不是引入新的错误。但是,如果我们想要在错误处理中进行特殊操作,例如记录错误并重新抛出,或者在某种条件下抛出新错误,这可能是有用的。下面是在.catch中抛出错误并试图改变promiss状态的例子:

let myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('Initial error'));
  }, 1000);
});

// 第一个catch捕获初始错误
myPromise
  .catch(initialError => {
    console.error('Caught initial error:', initialError.message);
    
    // 在.then()中尝试抛出新的错误,但这同样不会改变Promise的状态
    throw new Error('Additional error during handling');
  })
  .catch(additionalError => {
    console.error('Caught additional error:', additionalError.message);
  });

在这个例子中,我们创建了一个Promise,它在1秒后通过reject函数抛出一个初始错误。然后,第一个.catch捕获了这个初始错误,并打印出错误信息。在.catch的回调中,我们模拟了一个在处理错误时抛出新错误的情况,这会导致控制流跳转到下一个.catch,处理这个新的错误。这样,我们可以在错误处理链中进行一些自定义操作,但通常建议避免这样做,以免混淆错误处理流程。

4、对象的状态不受外界影响

        指一旦一个Promise被创建,它的状态(Pending、Fulfilled 或 Rejected)只能由内部的异步操作或回调函数来改变,而不是外部的直接干预。这保证了Promise状态的线性流程和一致性。

let myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    // 模拟异步操作
    if (Math.random() > 0.5) {
      resolve('Success!'); // 操作成功,改变状态为fulfilled
    } else {
      reject('Error!'); // 操作失败,改变状态为rejected
    }
  }, 1000);
});

// 尝试在外部改变Promise状态,这将不会有任何效果
myPromise.status = 'pending'; // 这行代码不会影响Promise的实际状态

// 正确处理Promise状态的方式
myPromise
  .then(result => {
    console.log('Promise fulfilled:', result);
  })
  .catch(error => {
    console.error('Promise rejected:', error);
  });

打印结果:

在这个例子中,myPromise 的状态由内部的异步操作(随机数生成)决定,外部尝试直接修改 status 属性是无效的。只有通过 resolve 或 reject 函数,状态才能从 pending 变为 fulfilled 或 rejected当状态改变后,它就不能再变回 pending也不能从 fulfilled 变为 rejected 或从rejected变为fulfilled。这就是Promise状态的不可变性。

后续会继续更新与async/await的结合...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值