近日,知名科技资讯平台XiaomiTime爆料,小米16系列三款旗舰手机——小米16、小米16 Pro、小米16 Ultra已完成认证,有望在9月发布...
2025-08-29 0
在前端开发的异步编程领域,我们常常会遇到需要处理多个异步操作的情况。早期,使用回调函数来处理异步操作是一种常见的方式,但这种方式在处理复杂的异步流程时,会带来一个让人头疼的问题 —— “回调地狱”。
假设我们有这样一个场景:李华向他的众多crush表白(人物纯属虚构,切勿带入个人)。使用传统的回调函数实现,代码可能会长这样:
function sendMessages(name, onFulfilled, onRejected) { console.log(`李华 to ${name}:我喜欢你`); console.log(`李华 等待 ${name}的回答`); setTimeout(() => { if (Math.random() <= 0.1) { // 调用成功之后的回调 onFulfilled(`李华,爱老虎油`) } else { // 调用失败之后的回调 onRejected(`李华,抱歉,我有别人追了`) } }, 1000)}sendMessages( "旺仔小乔", (reply) => { console.log("成功", reply) }, (reply) => { console.log("失败", reply); sendMessages( "可乐大乔", (reply) => { console.log("成功", reply); }, (reply) => { console.log("失败", reply); sendMessages( "伊利周瑜", (reply) => { console.log("成功", reply) }, (reply) => { console.log("失败", reply); sendMessages( "尖叫张飞", (reply) => { "成功", reply }, (reply) => { "失败", reply console.log("李华,这辈子也就这样了"); } ) } ) } ) })
这段代码虽然实现了我们的需求,但随着异步操作的增多,回调函数的嵌套会越来越深,代码会变得越来越难以阅读和维护。想象一下,如果这里有更多的文件需要读取,或者每个异步操作之间还有其他的逻辑,代码的复杂度将会呈指数级增长,这就是所谓的 “回调地狱”。
为了解决回调地狱的问题,ES6 引入了 Promise。Promise 是一个对象,它代表了一个异步操作的最终完成(或失败)及其结果值。简单来说,Promise 就是一个承诺,它承诺在未来的某个时间点会给你一个结果,这个结果可能是成功的数据,也可能是失败的原因。
使用 Promise 来改写上面读取文件的代码,会变得清晰很多:
sendMessages("旺仔小乔") .then( (reply) => { console.log("成功", reply); // 成功后返回一个已完成的Promise,终止链式调用 return Promise.resolve(); }, (reply) => { console.log("失败", reply); // 失败后返回新的Promise,继续下一个 return sendMessages("可乐大乔"); } ) .then( (reply) => { console.log("成功", reply); return Promise.resolve(); }, (reply) => { console.log("失败", reply); return sendMessages("伊利周瑜"); } ) .then( (reply) => { console.log("成功", reply); return Promise.resolve(); }, (reply) => { console.log("失败", reply); return sendMessages("尖叫张飞"); } ) .then( (reply) => { console.log("成功", reply); }, (reply) => { console.log("失败", reply); console.log("李华,这辈子也就这样了"); } );
在这段代码中,我们使用了 Promise 的链式调用,每个 then 方法都返回一个新的 Promise,这样就避免了回调函数的层层嵌套,使得代码的逻辑更加清晰,错误处理也更加统一。
在现代前端开发中,Promise 已经成为了处理异步操作的核心机制之一。无论是使用原生的 JavaScript 进行开发,还是使用各种前端框架(如 Vue、React 等),都离不开 Promise。掌握 Promise 的使用,不仅可以让我们写出更优雅、更易维护的异步代码,还能更好地理解和运用其他与异步相关的技术,如 async/await 等。因此,深入学习 Promise 是每一位前端开发者都必不可少的功课。
接下来,让我们深入了解 Promise 的基本概念和用法,看看它是如何工作的,以及如何在实际项目中灵活运用它来解决各种异步编程问题。
Promise 是 ES6 引入的一种异步编程的新解决方案,它是一个对象,代表了一个异步操作的最终完成(或成功)及其结果值。简单来说,Promise 就像是一个容器,里面保存着某个未来才会结束的事件(通常是异步操作)的结果。从语法上讲,Promise 是一个对象,通过它可以获取异步操作的消息,并且提供了统一的 API,使得各种异步操作都能用同样的方式进行处理。
Promise 有三种状态:
状态转换规则如下:
下面通过一个简单的示例来展示 Promise 的基本使用:
// 创建一个 Promiseconst myPromise = new Promise((resolve, reject) => { // 模拟异步操作,这里使用 setTimeout setTimeout(() => { const success = true; // 模拟操作结果 if (success) { resolve('操作成功'); // 将 Promise 状态置为 Fulfilled,并传递成功的值 } else { reject('操作失败'); // 将 Promise 状态置为 Rejected,并传递失败的原因 } }, 1000);});// 处理 Promise 的结果myPromise.then((result) => { console.log(result); // 输出: 操作成功}).catch((error) => { console.error(error); // 如果失败,捕获并输出错误});
在上述代码中,我们首先使用 new Promise 创建了一个 Promise 对象,在其执行器函数中,通过 setTimeout 模拟了一个异步操作。如果 success 为 true,则调用 resolve 方法将 Promise 的状态变为 Fulfilled,并传递成功的结果 '操作成功';如果 success 为 false,则调用 reject 方法将 Promise 的状态变为 Rejected,并传递失败的原因 '操作失败'。
然后,我们使用 then 方法来处理 Promise 成功的情况,在 then 的回调函数中,我们可以获取到 resolve 传递过来的成功结果并进行相应的处理。使用 catch 方法来处理 Promise 失败的情况,在 catch 的回调函数中,我们可以获取到 reject 传递过来的失败原因并进行错误处理。
then 方法是 Promise 中用于处理异步操作结果的核心方法之一,它允许我们在 Promise 状态变为 fulfilled 或 rejected 时执行相应的回调函数。
then 方法的一个重要特性是它返回一个新的 Promise,这使得我们可以进行链式调用。具体来说,then 方法接收两个可选参数:onFulfilled 和 onRejected。
当我们调用 then 方法时,它会返回一个新的 Promise,这个新 Promise 的状态和值取决于 then 方法中回调函数的执行结果:
通过这种方式,我们可以将多个 then 方法串联起来,形成一个链式调用,每个 then 方法处理前一个 Promise 的结果,并返回一个新的 Promise 供下一个 then 方法处理。
假设我们有一个需求,需要先获取用户信息,然后根据用户信息获取用户的订单列表,最后统计订单的总金额。使用 then 方法的链式调用可以很方便地实现这个需求:
// 模拟获取用户信息的异步操作function getUserInfo() { return new Promise((resolve, reject) => { setTimeout(() => { const user = { id: 1, name: 'John' }; resolve(user); }, 1000); });}// 模拟根据用户信息获取订单列表的异步操作function getOrderList(user) { return new Promise((resolve, reject) => { setTimeout(() => { const orders = [ { id: 1, amount: 100, userId: user.id }, { id: 2, amount: 200, userId: user.id } ]; resolve(orders); }, 1000); });}// 统计订单总金额function calculateTotalAmount(orders) { return orders.reduce((total, order) => total + order.amount, 0);}getUserInfo() .then(user => getOrderList(user)) .then(orders => calculateTotalAmount(orders)) .then(totalAmount => console.log(`订单总金额为: ${totalAmount}`)) .catch(error => console.error('操作过程中出现错误:', error));
在这个示例中,getUserInfo 返回一个 Promise,当这个 Promise 成功时,then 方法会调用 getOrderList 并传入用户信息,getOrderList 又返回一个 Promise,当这个 Promise 成功时,下一个 then 方法会调用 calculateTotalAmount 并传入订单列表,最后计算出订单总金额并打印。如果在任何一个步骤中出现错误,catch 方法会捕获并处理错误。
catch 方法是 Promise 中用于捕获错误的方法,它是 then 方法的语法糖,用于简化错误处理。
catch 方法实际上是 then(null, onRejected) 的简写形式,它专门用于捕获 Promise 链中任何一个环节抛出的错误。当 Promise 链中的某个 Promise 被拒绝(rejected)时,如果之前的 then 方法没有提供 onRejected 回调函数来处理错误,那么这个错误会一直向后传递,直到被 catch 方法捕获。
例如:
new Promise((resolve, reject) => { setTimeout(() => { reject('操作失败'); }, 1000);}) .then(result => console.log(result)) .catch(error => console.error('捕获到错误:', error));
在这个例子中,Promise 被拒绝并传递了错误信息 '操作失败',由于第一个 then 方法没有提供 onRejected 回调函数,所以错误会被后面的 catch 方法捕获并处理。
在项目中使用 catch 方法进行错误处理时,有一些最佳实践建议:
finally 方法是 ES9(ES2018) 引入的 Promise 方法,它的特点是无论 Promise 的状态是 fulfilled 还是 rejected,都会执行其中的回调函数。
finally 方法主要用于一些资源清理的场景,比如在异步操作完成后关闭文件、释放网络连接等。它的回调函数不接收任何参数,因为它不关心 Promise 的最终状态是成功还是失败。
例如,我们在使用 fetch 进行网络请求时,可以使用 finally 方法来显示加载状态的结束:
function fetchData() { console.log('开始加载数据...'); return fetch('https://api.example.com/data') .then(response => response.json()) .catch(error => console.error('请求出错:', error)) .finally(() => console.log('数据加载结束'));}fetchData();
在这个例子中,无论 fetch 请求成功还是失败,finally 方法中的回调函数都会执行,打印出 '数据加载结束',这样可以确保加载状态的显示与实际的异步操作完成情况一致。
Promise.all 方法用于并行处理多个异步任务,它接收一个包含多个 Promise 对象的可迭代对象(如数组)作为参数,并返回一个新的 Promise。只有当传入的所有 Promise 都成功完成(状态变为 fulfilled)时,返回的新 Promise 才会成功,其结果是一个包含所有成功结果的数组,且数组中结果的顺序与传入的 Promise 顺序一致。如果其中任何一个 Promise 失败(状态变为 rejected),则返回的新 Promise 会立即失败,失败原因是第一个失败的 Promise 的错误信息。
例如,我们有三个异步任务,分别模拟从不同的 API 获取数据:
function fetchData1() { return new Promise((resolve) => { setTimeout(() => { resolve('数据1'); }, 1000); });}function fetchData2() { return new Promise((resolve) => { setTimeout(() => { resolve('数据2'); }, 2000); });}function fetchData3() { return new Promise((resolve) => { setTimeout(() => { resolve('数据3'); }, 1500); });}Promise.all([fetchData1(), fetchData2(), fetchData3()]) .then(results => { console.log(results); // 输出: ['数据1', '数据2', '数据3'] }) .catch(error => { console.error(error); });
在这个例子中,Promise.all 会同时启动这三个异步任务,尽管它们的完成时间不同,但最终会等待所有任务都完成后,将结果以数组的形式返回。如果其中某个任务失败,比如 fetchData2 改为:
function fetchData2() { return new Promise((_, reject) => { setTimeout(() => { reject('获取数据2失败'); }, 2000); });}
那么 Promise.all 返回的 Promise 会立即失败,catch 方法会捕获到错误信息 '获取数据2失败'。
在一个电商项目中,我们可能需要在商品详情页面展示商品的基本信息、评论列表和相关推荐商品。这些数据分别来自不同的 API 接口,我们可以使用 Promise.all 来并发请求这些数据,从而提高页面的加载效率。
// 获取商品基本信息function getProductInfo(productId) { return fetch(`https://api.example.com/products/${productId}`) .then(response => response.json());}// 获取商品评论列表function getProductReviews(productId) { return fetch(`https://api.example.com/products/${productId}/reviews`) .then(response => response.json());}// 获取相关推荐商品function getRelatedProducts(productId) { return fetch(`https://api.example.com/products/${productId}/related`) .then(response => response.json());}const productId = 123;Promise.all([ getProductInfo(productId), getProductReviews(productId), getRelatedProducts(productId)]) .then(([productInfo, reviews, relatedProducts]) => { // 处理数据,展示在页面上 console.log('商品基本信息:', productInfo); console.log('商品评论列表:', reviews); console.log('相关推荐商品:', relatedProducts); }) .catch(error => { console.error('请求数据失败:', error); });
通过这种方式,我们可以并行地获取这三个数据,而不需要依次等待每个请求完成,大大缩短了页面的加载时间,提升了用户体验。如果其中任何一个请求失败,整个 Promise.all 就会失败,我们可以在 catch 方法中统一处理错误。
Promise.race 方法同样接收一个包含多个 Promise 对象的可迭代对象作为参数,并返回一个新的 Promise。它的特点是,只要传入的 Promise 中有一个率先完成(无论是成功还是失败),返回的新 Promise 就会立即以这个率先完成的 Promise 的结果或错误进行解决或拒绝。
例如,我们有两个异步任务,一个任务模拟成功响应,另一个任务模拟失败响应:
function task1() { return new Promise((resolve) => { setTimeout(() => { resolve('任务1成功'); }, 2000); });}function task2() { return new Promise((_, reject) => { setTimeout(() => { reject('任务2失败'); }, 1000); });}Promise.race([task1(), task2()]) .then(result => { console.log(result); // 不会执行 }) .catch(error => { console.error(error); // 输出: 任务2失败 });
在这个例子中,task2 会在 1 秒后失败,而 task1 需要 2 秒后才成功,所以 Promise.race 返回的 Promise 会立即失败,错误信息为 '任务2失败'。
Promise.race 常用于设置请求超时的场景。比如,我们发起一个网络请求获取数据,但希望在一定时间内如果没有收到响应,就视为请求超时并进行相应处理:
function fetchData() { return fetch('https://api.example.com/data') .then(response => response.json());}function timeout(duration) { return new Promise((_, reject) => { setTimeout(() => { reject(new Error('请求超时')); }, duration); });}Promise.race([fetchData(), timeout(3000)]) .then(data => { console.log('请求成功:', data); }) .catch(error => { console.error('请求失败:', error.message); });
在这个例子中,fetchData 发起网络请求获取数据,timeout(3000) 创建一个 3 秒后失败的 Promise。Promise.race 会同时执行这两个 Promise,如果 fetchData 在 3 秒内成功获取数据,就会执行 then 方法处理数据;如果 3 秒内 fetchData 没有完成,timeout 会率先失败,Promise.race 返回的 Promise 就会失败,执行 catch 方法,提示请求超时。
Promise.allSettled 方法也接收一个包含多个 Promise 对象的可迭代对象作为参数,并返回一个新的 Promise。与 Promise.all 不同的是,Promise.allSettled 会等待所有传入的 Promise 都有结果(无论成功还是失败),然后返回一个包含所有 Promise 状态和结果的数组。数组中的每个元素是一个对象,包含 status(表示 Promise 的状态,取值为 'fulfilled' 或 'rejected')和 value(如果状态是 fulfilled,则为成功的结果;如果状态是 rejected,则为失败的原因)。
例如:
function task1() { return new Promise((resolve) => { setTimeout(() => { resolve('任务1成功'); }, 1000); });}function task2() { return new Promise((_, reject) => { setTimeout(() => { reject('任务2失败'); }, 2000); });}Promise.allSettled([task1(), task2()]) .then(results => { results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`任务${index + 1}成功,结果为:`, result.value); } else { console.log(`任务${index + 1}失败,原因是:`, result.reason); } }); });
在这个例子中,Promise.allSettled 会等待 task1 和 task2 都有结果后,返回一个包含两个对象的数组。第一个对象表示 task1 的状态和结果,第二个对象表示 task2 的状态和原因。通过这种方式,我们可以全面了解每个异步任务的执行情况,而不会因为某个任务的失败而中断对其他任务结果的处理。
Promise.allSettled 适用于一些需要对多个异步操作的结果进行汇总分析的场景。比如在一个批量数据处理的任务中,我们需要向多个服务器发送数据更新请求,无论每个请求是否成功,都需要记录下每个请求的结果,以便后续进行错误排查和统计分析:
function updateServer1(data) { return new Promise((resolve, reject) => { // 模拟网络请求 setTimeout(() => { if (Math.random() > 0.5) { resolve('服务器1更新成功'); } else { reject('服务器1更新失败'); } }, 1000); });}function updateServer2(data) { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('服务器2更新成功'); } else { reject('服务器2更新失败'); } }, 1500); });}const data = { key: 'value' };Promise.allSettled([updateServer1(data), updateServer2(data)]) .then(results => { let successCount = 0; let failureCount = 0; results.forEach((result, index) => { if (result.status === 'fulfilled') { successCount++; console.log(`服务器${index + 1}更新成功,结果为:`, result.value); } else { failureCount++; console.log(`服务器${index + 1}更新失败,原因是:`, result.reason); } }); console.log(`成功更新的服务器数量: ${successCount}`); console.log(`更新失败的服务器数量: ${failureCount}`); });
在这个例子中,Promise.allSettled 可以帮助我们统计出成功和失败的服务器更新次数,方便对整个批量更新操作的结果进行评估和后续处理。
Promise.any 方法接收一个包含多个 Promise 对象的可迭代对象作为参数,并返回一个新的 Promise。它的特性是只要传入的 Promise 中有一个成功(状态变为 fulfilled),返回的新 Promise 就会立即成功,其结果就是第一个成功的 Promise 的结果。如果所有传入的 Promise 都失败(状态变为 rejected),则返回的新 Promise 会失败,并抛出一个 AggregateError 错误,该错误包含所有失败的原因。
例如:
function task1() { return new Promise((_, reject) => { setTimeout(() => { reject('任务1失败'); }, 2000); });}function task2() { return new Promise((resolve) => { setTimeout(() => { resolve('任务2成功'); }, 1000); });}function task3() { return new Promise((_, reject) => { setTimeout(() => { reject('任务3失败'); }, 1500); });}Promise.any([task1(), task2(), task3()]) .then(result => { console.log('第一个成功的任务结果:', result); // 输出: 任务2成功 }) .catch(error => { console.error('所有任务都失败:', error); });
在这个例子中,task2 会在 1 秒后成功,虽然 task1 和 task3 会失败,但 Promise.any 只关注第一个成功的 Promise,所以会立即返回 task2 的成功结果。
Promise.any 适用于需要获取第一个成功结果的场景。比如在一个应用中,我们有多个数据源可以获取用户的偏好设置,但只要从其中一个数据源成功获取到数据,就可以满足需求,不需要等待其他数据源的响应:
function fetchPreferencesFromSource1() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve({ theme: 'dark' }); } else { reject('数据源1获取失败'); } }, 1000); });}function fetchPreferencesFromSource2() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve({ language: 'en' }); } else { reject('数据源2获取失败'); } }, 1500); });}function fetchPreferencesFromSource3() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve({ notifications: true }); } else { reject('数据源3获取失败'); } }, 2000); });}Promise.any([fetchPreferencesFromSource1(), fetchPreferencesFromSource2(), fetchPreferencesFromSource3()]) .then(preferences => { console.log('获取到用户偏好设置:', preferences); }) .catch(error => { console.error('所有数据源获取失败:', error); });
在这个例子中,只要有一个数据源成功获取到用户偏好设置,Promise.any 就会返回该结果,从而快速满足应用对用户偏好数据的需求。如果所有数据源都获取失败,catch 方法会捕获到 AggregateError 错误,我们可以根据具体情况进行处理,比如提示用户获取偏好设置失败。
async/await 是 ES2017 引入的异步编程语法糖,它建立在 Promise 的基础之上,使得异步代码看起来更像是同步代码,极大地提升了代码的可读性和可维护性 。async 用于声明一个异步函数,该函数始终返回一个 Promise 对象。await 关键字只能在 async 函数内部使用,用于等待一个 Promise 对象的解决(resolved)或拒绝(rejected),它会暂停当前 async 函数的执行,直到被等待的 Promise 对象返回结果。
例如:
async function asyncFunction() { try { const result = await new Promise((resolve) => { setTimeout(() => { resolve('异步操作结果'); }, 1000); }); console.log(result); // 输出: 异步操作结果 } catch (error) { console.error(error); }}asyncFunction();
在这个例子中,asyncFunction 是一个异步函数,await 等待 new Promise 返回的结果,当 Promise 成功解决后,await 会将结果赋值给 result,然后继续执行后面的代码。如果 Promise 被拒绝,catch 块会捕获到错误并进行处理。
function getUserInfo() { return new Promise((resolve) => { setTimeout(() => { const user = { id: 1, name: 'John' }; resolve(user); }, 1000); });}function getOrderList(user) { return new Promise((resolve) => { setTimeout(() => { const orders = [ { id: 1, amount: 100, userId: user.id }, { id: 2, amount: 200, userId: user.id } ]; resolve(orders); }, 1000); });}getUserInfo() .then(user => getOrderList(user)) .then(orders => console.log(orders)) .catch(error => console.error(error));
async function getUserAndOrders() { try { const user = await getUserInfo(); const orders = await getOrderList(user); console.log(orders); } catch (error) { console.error(error); }}getUserAndOrders();
可以看出,async/await 的写法更加简洁直观,代码结构更接近同步代码,阅读起来更容易理解。
在实际项目中,async/await 常用于处理网络请求、数据库操作等异步任务。以一个简单的前端项目为例,我们使用 fetch 进行网络请求获取数据,并使用 async/await 进行处理:
<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>async/await 示例</title></head><body> <script> async function fetchData() { try { const response = await fetch('https://jsonplaceholder.typicode.com/posts/1'); if (!response.ok) { throw new Error('网络请求失败'); } const data = await response.json(); console.log(data); } catch (error) { console.error('获取数据失败:', error); } } fetchData(); </script></body></html>
在这段代码中,fetchData 是一个异步函数,使用 await 等待 fetch 请求返回的 Promise 对象,然后检查响应状态,如果状态正常,再等待解析 JSON 数据。如果在任何一步出现错误,catch 块会捕获并处理错误。这种写法使得网络请求的处理逻辑更加清晰,易于理解和维护。通过这个示例,我们可以看到 async/await 在实际项目中的应用场景和优势,它让异步编程变得更加简单和高效。
Promise 的核心是一个状态机,它的内部机制涉及到状态管理、任务队列以及微任务与宏任务的处理。
console.log('script start');setTimeout(() => { console.log('setTimeout');}, 0);Promise.resolve() .then(() => { console.log('promise1'); }) .then(() => { console.log('promise2'); });console.log('script end');
在这段代码中,首先输出script start和script end,这是同步代码的执行。然后setTimeout被放入宏任务队列,Promise.resolve().then被放入微任务队列。由于微任务优先于宏任务执行,所以先输出promise1和promise2,最后输出setTimeout。通过这样的机制,Promise 实现了异步操作的有序处理和回调函数的延迟执行,使得异步编程更加可控和可预测。
为了更深入地理解 Promise 的工作原理,我们可以手写一个简易版的 Promise。下面是一个基本的实现,它包含了 Promise 的核心功能:状态管理、then方法的链式调用以及错误处理。
const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED ='rejected';class MyPromise { constructor(executor) { this.state = PENDING; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === PENDING) { this.state = FULFILLED; this.value = value; this.onFulfilledCallbacks.forEach(callback => callback(this.value)); } }; const reject = (reason) => { if (this.state === PENDING) { this.state = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach(callback => callback(this.reason)); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function'? onFulfilled : value => value; onRejected = typeof onRejected === 'function'? onRejected : reason => { throw reason }; return new MyPromise((nextResolve, nextReject) => { if (this.state === FULFILLED) { setTimeout(() => { try { const x = onFulfilled(this.value); this.#resolvePromise(nextResolve, nextReject, x); } catch (error) { nextReject(error); } }, 0); } if (this.state === REJECTED) { setTimeout(() => { try { const x = onRejected(this.reason); this.#resolvePromise(nextResolve, nextReject, x); } catch (error) { nextReject(error); } }, 0); } if (this.state === PENDING) { this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { const x = onFulfilled(this.value); this.#resolvePromise(nextResolve, nextReject, x); } catch (error) { nextReject(error); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { const x = onRejected(this.reason); this.#resolvePromise(nextResolve, nextReject, x); } catch (error) { nextReject(error); } }, 0); }); } }); } catch(onRejected) { return this.then(null, onRejected); } #resolvePromise(nextResolve, nextReject, x) { if (x === this) { return nextReject(new TypeError('Chaining cycle detected for promise')); } if (x instanceof MyPromise) { x.then(nextResolve, nextReject); } else if (x!== null && (typeof x === 'object' || typeof x === 'function')) { let called = false; try { const then = x.then; if (typeof then === 'function') { then.call(x, (y) => { if (called) return; called = true; this.#resolvePromise(nextResolve, nextReject, y); }, (r) => { if (called) return; called = true; nextReject(r); }); } else { nextResolve(x); } } catch (error) { if (called) return; called = true; nextReject(error); } } else { nextResolve(x); } }}
在这个实现中:
随着前端技术的不断发展,异步编程将继续在前端开发中扮演重要的角色。希望透过这篇文章让大家理解Promise,Promise 作为异步编程的基础,也将不断演进和完善。希望大家在今后的前端开发中,能够熟练运用 Promise,让我们的代码更加优雅、高效!如果大家在学习和使用 Promise 的过程中有任何问题或心得,欢迎在评论区留言交流
相关文章
近日,知名科技资讯平台XiaomiTime爆料,小米16系列三款旗舰手机——小米16、小米16 Pro、小米16 Ultra已完成认证,有望在9月发布...
2025-08-29 0
您好:这款游戏是可以开挂的,软件加微信【添加图中微信】确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到其他人...
2025-08-29 0
现在人们打棋牌麻将谁不想赢?手机微乐麻将必赢神器但是手机棋牌麻将是这么好赢的吗?在手机上打棋牌麻将想赢,不仅需要运气,也需要技巧。掌握的棋牌麻将技巧就...
2025-08-29 0
您好:这款游戏可以开挂,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到-人的牌一样。所以很多小伙伴就怀疑这...
2025-08-29 0
又一架比沈六代和银杏叶还科幻的飞机?随着沈六代和银杏叶的试飞,标志着东大航空工业着实进入了军机设计与制造的自由王国。自此之后,尤其是在近段时间内,先后...
2025-08-29 0
型号25098PN5AC、2509FPN0BC、25113PN0EC三款新机悄然现身工信部网站,100W有线闪充的标识格外醒目,小米16系列的旗舰之战...
2025-08-29 0
IT之家 8 月 29 日消息,微软宣布,从 9 月 9 日的“星期二更新”开始,将正式终止对 Windows 域控制器中两项注册表键的技术支持,此前...
2025-08-29 1
发表评论