前端必会:Promise 全解析,从原理到实战

【前端必看:Promise全解析,一文融会贯通!】 本文深入介绍了JavaScript中的Promise及其应用。首先通过回调地狱问题展示了传统异步编程的痛点,进而引出Promise解决方案。详细讲解了Promise的三种状态(pending/fulfilled/rejected)和基本用法,包括then、catch、finally等核心方法。还介绍了Promise.all()、Promise.race()等高级方法的使用场景,全文通过丰富示例演示了Promise如何优雅地处理异步操作,帮助开发者编写更清晰、易维护的代码 阅读详情

1. 从 “回调地狱” 到 Promise

在前端开发的异步编程领域,我们常常会遇到需要处理多个异步操作的情况。早期,使用回调函数来处理异步操作是一种常见的方式,但这种方式在处理复杂的异步流程时,会带来一个让人头疼的问题 —— “回调地狱”。

1.1 回调地狱示例

假设我们有这样一个场景:李华向他的众多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("李华,这辈子也就这样了");
                            }
                        )
                    }
                )
            }
        )
    }
)

这段代码虽然实现了我们的需求,但随着异步操作的增多,回调函数的嵌套会越来越深,代码会变得越来越难以阅读和维护。想象一下,如果这里有更多的文件需要读取,或者每个异步操作之间还有其他的逻辑,代码的复杂度将会呈指数级增长,这就是所谓的 “回调地狱”。

1.2 回调地狱的问题

  • 代码可读性差:层层嵌套的回调函数使得代码的逻辑结构变得模糊,难以一眼看出各个异步操作之间的关系和执行顺序。
  • 维护困难:当需要修改其中某个异步操作的逻辑时,可能需要在多层嵌套中找到对应的回调函数,并且还要小心不影响其他部分的代码。
  • 错误处理复杂:每个回调函数都需要单独处理错误,这不仅增加了代码量,还容易出现错误处理不一致的情况。

1.3 Promise 应运而生

为了解决回调地狱的问题,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,这样就避免了回调函数的层层嵌套,使得代码的逻辑更加清晰,错误处理也更加统一。

1.4 学习 Promise 的重要性

在现代前端开发中,Promise 已经成为了处理异步操作的核心机制之一。无论是使用原生的 JavaScript 进行开发,还是使用各种前端框架(如 Vue、React 等),都离不开 Promise。掌握 Promise 的使用,不仅可以让我们写出更优雅、更易维护的异步代码,还能更好地理解和运用其他与异步相关的技术,如 async/await 等。因此,深入学习 Promise 是每一位前端开发者都必不可少的功课。

接下来,让我们深入了解 Promise 的基本概念和用法,看看它是如何工作的,以及如何在实际项目中灵活运用它来解决各种异步编程问题。

2. Promise 初相识 (Promise A+规范)

2.1 概念与定义

Promise 是 ES6 引入的一种异步编程的新解决方案,它是一个对象,代表了一个异步操作的最终完成(或成功)及其结果值。简单来说,Promise 就像是一个容器,里面保存着某个未来才会结束的事件(通常是异步操作)的结果。从语法上讲,Promise 是一个对象,通过它可以获取异步操作的消息,并且提供了统一的 API,使得各种异步操作都能用同样的方式进行处理。

2.2 三个状态

Promise 有三种状态:

  • Pending(等待态) :这是 Promise 的初始状态,此时异步操作尚未完成,既没有被兑现(成功)也没有被拒绝(失败)。
  • Fulfilled(成功态) :当异步操作成功完成时,Promise 的状态会变为 Fulfilled,意味着操作已经成功,我们可以从 Promise 中获取到预期的结果。此时,Promise 会携带一个值,这个值就是异步操作成功的结果。
  • Rejected(失败态) :如果异步操作失败或出现错误,Promise 的状态会变为 Rejected。此时,Promise 会携带一个原因,表示失败的原因。

状态转换规则如下:

  • 一个 Promise 一旦从 Pending 状态变为 Fulfilled 或 Rejected,就不可以再进行其他状态转变,即 Promise 的状态只能改变一次。
  • Promise 只能从 Pending 状态转换成 Fulfilled 或 Rejected 状态。具体转换流程为:当异步操作成功完成时,状态从 Pending 变为 Fulfilled,未来可以用 .then() 方法访问结果;当异步操作失败时,状态从 Pending 变为 Rejected,未来可以用 .catch() 方法访问错误信息 。

2.3 基本用法示例

下面通过一个简单的示例来展示 Promise 的基本使用:

// 创建一个 Promise
const 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 传递过来的失败原因并进行错误处理。

3. Promise 的核心方法

3.1 then 方法

then 方法是 Promise 中用于处理异步操作结果的核心方法之一,它允许我们在 Promise 状态变为 fulfilled 或 rejected 时执行相应的回调函数。

3.1.1 链式调用原理

then 方法的一个重要特性是它返回一个新的 Promise,这使得我们可以进行链式调用。具体来说,then 方法接收两个可选参数:onFulfilled 和 onRejected。

  • onFulfilled:当 Promise 状态变为 fulfilled 时调用的回调函数,该函数接收 Promise 成功时的值作为参数。
  • onRejected:当 Promise 状态变为 rejected 时调用的回调函数,该函数接收 Promise 失败时的原因作为参数。

当我们调用 then 方法时,它会返回一个新的 Promise,这个新 Promise 的状态和值取决于 then 方法中回调函数的执行结果:

  • 如果 onFulfilled 或 onRejected 回调函数返回一个值,这个值会被包装成一个新的已解决(resolved)的 Promise,并作为 then 方法返回的新 Promise 的值。
  • 如果 onFulfilled 或 onRejected 回调函数抛出一个错误,这个错误会被包装成一个新的已拒绝(rejected)的 Promise,并作为 then 方法返回的新 Promise 的值。
  • 如果 onFulfilled 或 onRejected 回调函数返回一个 Promise,那么 then 方法返回的新 Promise 的状态和值将取决于这个返回的 Promise 的状态和值。

通过这种方式,我们可以将多个 then 方法串联起来,形成一个链式调用,每个 then 方法处理前一个 Promise 的结果,并返回一个新的 Promise 供下一个 then 方法处理。

3.1.2 示例与应用场景

假设我们有一个需求,需要先获取用户信息,然后根据用户信息获取用户的订单列表,最后统计订单的总金额。使用 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 方法会捕获并处理错误。

3.2 catch 方法

catch 方法是 Promise 中用于捕获错误的方法,它是 then 方法的语法糖,用于简化错误处理。

3.2.1 错误捕获机制

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 方法捕获并处理。

3.2.2 错误处理最佳实践

在项目中使用 catch 方法进行错误处理时,有一些最佳实践建议:

  • 统一错误处理:在 Promise 链的末尾使用 catch 方法来捕获所有可能的错误,这样可以确保错误不会被遗漏,并且可以在一个地方统一处理错误。
  • 错误日志记录:在 catch 方法中,除了对错误进行处理外,还应该记录错误日志,以便后续排查问题。可以使用浏览器的控制台日志或者专业的日志记录工具。
  • 避免在 catch 中抛出新错误:尽量避免在 catch 方法中再次抛出新的错误,因为这会导致错误处理变得更加复杂,并且可能会使错误在 Promise 链中继续传递,难以追踪。如果确实需要在 catch 中处理错误后返回一个新的 Promise,应该使用 resolve 或 reject 来处理,而不是抛出新错误。

3.3 finally 方法

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 方法中的回调函数都会执行,打印出 '数据加载结束',这样可以确保加载状态的显示与实际的异步操作完成情况一致。

4. Promise 的高级应用

4.1 Promise.all

4.1.1 并发请求处理

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失败'。

4.1.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 方法中统一处理错误。

4.2 Promise.race

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 方法,提示请求超时。

4.3 Promise.allSettled

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 可以帮助我们统计出成功和失败的服务器更新次数,方便对整个批量更新操作的结果进行评估和后续处理。

4.4 Promise.any

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 错误,我们可以根据具体情况进行处理,比如提示用户获取偏好设置失败。

5. Promise 与 async/await

5.1 async/await 语法糖

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 块会捕获到错误并进行处理。

5.2 对比与优势

  • 写法对比:使用 Promise 时,我们通过链式调用 then 方法来处理异步操作的结果,而 async/await 则通过 await 关键字来等待 Promise 的结果,使代码看起来更像同步代码。例如,同样是获取用户信息并根据用户信息获取订单列表的操作:
  • Promise 写法:
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/await 写法:
async function getUserAndOrders() {
    try {
        const user = await getUserInfo();
        const orders = await getOrderList(user);
        console.log(orders);
    } catch (error) {
        console.error(error);
    }
}
getUserAndOrders();

可以看出,async/await 的写法更加简洁直观,代码结构更接近同步代码,阅读起来更容易理解。

  • 错误处理优势:在 Promise 中,错误处理通常通过 catch 方法在链式调用的末尾进行捕获。而在 async/await 中,可以使用传统的 try...catch 语句来捕获错误,这种方式更加符合我们处理同步代码错误的习惯,使得错误处理的代码位置更清晰,也更容易维护。例如,在上面的代码中,如果 getUserInfo 或 getOrderList 抛出错误,在 Promise 写法中,需要在最后一个 then 方法之后的 catch 中处理;而在 async/await 写法中,可以直接在 try 块中捕获并在 catch 块中处理,更方便定位和处理错误。

5.3 实际应用示例

在实际项目中,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 在实际项目中的应用场景和优势,它让异步编程变得更加简单和高效。

6. Promise 的原理与实现

6.1 内部机制剖析

Promise 的核心是一个状态机,它的内部机制涉及到状态管理、任务队列以及微任务与宏任务的处理。

  • 状态管理:Promise 有三种状态:Pending(等待态)、Fulfilled(成功态)和Rejected(失败态)。状态的转换是单向且不可逆的,一旦从Pending状态转变为Fulfilled或Rejected状态,就不能再发生改变。当我们创建一个 Promise 时,它会初始化为Pending状态。在异步操作完成后,根据结果调用resolve函数将状态转变为Fulfilled,并传递成功的值;或者调用reject函数将状态转变为Rejected,并传递失败的原因。
  • 任务队列:Promise 内部维护了一个任务队列,用于存储在then方法中注册的回调函数。当 Promise 的状态发生改变时,会触发任务队列中的回调函数执行。例如,当状态变为Fulfilled时,会依次执行任务队列中onFulfilled回调函数;当状态变为Rejected时,会依次执行onRejected回调函数 。
  • 微任务与宏任务:在 JavaScript 的事件循环机制中,任务分为宏任务(macrotask)和微任务(microtask)。宏任务如setTimeout、setInterval、script(整体代码)等,微任务如Promise.then、MutationObserver等。Promise 的then方法注册的回调函数属于微任务。当一个宏任务执行完毕后,会先检查微任务队列,并依次执行微任务队列中的所有任务,然后再去执行下一个宏任务。这就保证了 Promise 的then回调函数总是在当前宏任务结束后,下一个宏任务开始前执行。例如:
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 实现了异步操作的有序处理和回调函数的延迟执行,使得异步编程更加可控和可预测。

6.2 手写 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);
        }
    }
}

在这个实现中:

  • constructor方法接收一个执行器函数executor,并初始化 Promise 的状态为PENDING,同时定义了用于存储成功值value、失败原因reason以及成功和失败回调函数的数组onFulfilledCallbacks和onRejectedCallbacks。在执行器函数中,调用resolve和reject函数来改变 Promise 的状态,并触发相应的回调函数。
  • then方法用于处理 Promise 的成功和失败情况。它接收两个回调函数onFulfilled和onRejected,并返回一个新的 Promise。在then方法中,根据当前 Promise 的状态,决定是立即执行回调函数,还是将回调函数添加到相应的回调函数数组中等待状态改变时执行。如果回调函数返回一个值,会根据这个值的类型来决定如何处理新的 Promise;如果返回的是一个 Promise,则等待这个 Promise 完成后再决定新 Promise 的状态。
  • catch方法是then(null, onRejected)的简写,用于捕获 Promise 链中的错误。
  • resolvePromise方法是一个内部方法,用于处理then方法中回调函数返回值为 Promise 或者其他对象的情况,确保正确地处理链式调用和状态传递。通过这个简易版的 Promise 实现,我们可以更清晰地看到 Promise 的工作原理,包括状态的管理、回调函数的执行以及链式调用的实现机制,有助于我们在实际开发中更好地理解和运用 Promise。

随着前端技术的不断发展,异步编程将继续在前端开发中扮演重要的角色。希望透过这篇文章让大家理解Promise,Promise 作为异步编程的基础,也将不断演进和完善。希望大家在今后的前端开发中,能够熟练运用 Promise,让我们的代码更加优雅、高效!如果大家在学习和使用 Promise 的过程中有任何问题或心得,欢迎在评论区留言交流

Vue全家桶、Promise、NodeJS、全栈SSR、金融项目前端架构实战 1、带你探究vue-router源码,实现一个基础的vue-router 【课程大纲】 1、vue-router的原理是什么? 2、如何写一个vue-router 3、如何加固代码 2、再次探究vue源码,制作优秀的自定义插件库 vue成神之路--自定义插件库及NPM集成 【课程大纲】 1、插件与组件 2、如何制作一个优秀的插件库 3、集成至npm官网,向世界绽... 阅读详情

相关推荐

前端必备:从头开始,搞懂Promise之Promise基础

Promise的基础及延申,一点一点将promise基础及其相关拓展,都搞明白

Cheirre的博客 3267

前端 JS 经典:Promise 详解

在以前我们实现异步是用的回调函数,当一个异步请求需要依赖上一个异步请求返回的结果的时候,就会形成如下这种的调用结构。这种结构看着很杂乱且不易维护,被我们亲切的叫做。为了解决回调地狱的问题,Promise 就诞生了。。

weixin_64684095的博客 9654

promise规范和应用

(5)LocalStorage:是前端常用的本地存储机制,能够在不同页面之间存储和读取数据,当LocalStorage的值发生变化时,会触发storage事件,在发送消息时将消息写入LocalStorage,然后在各个页面中通过监听storage事件来接收消息。(3)Shared Worker:也是一个在后台运行的脚本,但与Service Worker不同的是可以被多个页面共享,需要在页面创建一个Shared Worker实例,并通过它来接受和发送消息。(4)本地存储数据问题;

blingblingBin的博客 1961

Promise源码解密-Promise A+标准

术语 1. Promise promise 是一个拥有 then 方法的 object 或 function ,其行为符合本规范 2. thenable 是一个定义了 then 方法的 object 或 function 3. 值(value) 指任何 JavaScript 的合法值(包括 undefined , thenable 和 promise); 4. 异常(exception) 通过throw抛出一个值 5. 原因(reason) 一个promise被拒绝的原因 class Promise

专注于图像领域,主要研究内容包括计算机视觉和深度学习,特别是在图像分类、目标检测和图像生成等方面有深入的研究和实践经验。 6167

前端 Promise 全面深入解析

使用.catch()或try/catch处理Promise拒绝避免嵌套Promise,保持代码可读性在.then中始终返回某些内容使异步代码更易读,类似同步代码使用处理并行操作优先使用和避免不必要的Promise,批量处理并发请求实现可取消的Promise(使用AbortController)确保测试覆盖所有状态(成功、失败、等待)利用ES2020的和。

weixin_43822134的博客 891

【Web前端】Promise的使用

Promise是异步编程的核心概念之一。代表一个可能尚未完成的操作,并提供了一种机制来处理该操作最终的成功或失败。具体来说,Promise是由异步函数返回的对象,能够指示该操作当前所处的状态。

一条晒干的咸鱼的博客 1776

前端Promise

一、Promise的理解与使用 抽象表达: Promise是ES6新增的一种语法,是异步编程的一种解决方案。(旧方案是单纯的使用回调函数) 异步编程:fs文件操作、数据库操作、Ajax、定时器。 具体表达: (1)从语法上说,promise是一种构造函数 (2)从功能上说,promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值。 1. Promise的状态 三种状态: pending(初始状态) f......

yin_ping1101的博客 1万+

无人机信号干扰系统设计方案

设计定向阻塞干扰器需要结合射频(RF)技术、功率放大技术和定向天线技术,核心目标是向特定方向发射高功率噪声信号,覆盖目标频段,阻断无人机的通信或导航信号。实际设计中需平衡功率、效率、散热和便携性,同时需考虑抗干扰技术的快速演进(如无人机加密通信和AI避障)。在合法框架下,此类设备可有效应对“黑飞”威胁,但技术滥用风险需严格管控。定向阻塞干扰器的硬件设计核心在于。

wanghao312的博客 3061

什么是Promise?前端开发人员会使用Promise简直就是如虎添翼

一、什么是Promise 1.Promise到底是做什么的呢? Promise是异步编程的种解决方案 那什么时候我们会来处理异步事件呢? 一种很常见的场景应该就是网络请求了。 我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7—样将结果返回。 所以往往我们会传入另外—个函数,在数据请求成功时,将数据通过传入的函数回调出去。 如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦 但是,当网络请求非常...

秃了也弱了 3808

英飞凌TC3xx的GTM模块到底有多强?从PWM生成到电机驱动,一篇讲透车载定时器核心

本文深入解析英飞凌TC3xx系列中的GTM模块在汽车电子领域的强大功能,从PWM生成到电机驱动的全链路设计。通过模块化架构和硬件级解决方案,GTM显著提升系统精度和响应速度,适用于电机控制、电源管理等复杂场景。文章结合实战经验,详细拆解GTM的技术实现和性能优势。

weixin_27741699的博客 204

SAP PPDS启发式排产实战:从零配置到自定义规则开发(附ABAP代码示例)

本文详细介绍了SAP PPDS启发式排产的实战应用,从基础配置到自定义规则开发的全流程。通过ABAP代码示例,展示了如何实现多目标优化、实时响应和约束可视化,帮助企业提升订单交付率、减少设备闲置时间。文章还包含开发环境准备、标准模板解析、自定义开发步骤及性能优化技巧,适合制造业数字化转型的实践参考。

seed的博客 185

前端Promise总结笔记

一.什么是Promise: Promise 是在 js 中进行异步编程的新解决方案。(以前旧的方案是单纯使用回调函数) 从语法来说,promise是一个构造函数。 从功能来说,promise对象用来封装一个异步操作,并且可以获得成功或失败的返回值。 二.为啥使用Promise: promise使用回调函数更灵活。旧的回调函数必须在启动异步任务前指定。 promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至能在异步任务结束后指定多个) pr

你好呀,很高兴你在看这里~ 1万+

闲鱼客户端三重动态签名机制解析:x-sign、x-mini-wua与x-umt

在移动客户端安全通信中,设备级动态签名已成为主流App防范自动化攻击的核心手段。其原理是将设备指纹、运行时行为与可信硬件标识深度融合,生成不可复用、不可跨端、不可静态伪造的请求凭证。这类机制超越传统Token或Session鉴权,具备强上下文绑定性与实时熵值校验能力,广泛应用于电商、社交及开放平台等高风险接口场景。技术价值体现在有效识别模拟器、无头浏览器与集群化爬虫,同时保障多端一致性与合规数据对接。本文聚焦闲鱼客户端实际落地的x-sign(带设备上下文的混合签名)、x-mini-wua(小程序行为水印)与

weixin_35732273的博客 497

前端必会:Promise多请求+finally+链式调用避坑指南

写这篇的时候,我又想起那个凌晨三点的厕所隔间。那时候我觉得Promise是世界上最难的东西,现在回头看,其实就那么几个概念:状态、then、catch、finally,再加上all/race这些工具方法。但编程就是这样,难的不是概念,是细节。哪个then忘了return、catch放错位置、finally里想改数据…这些坑不踩一遍,看十遍文档也记不住。所以我把这些血泪史都写出来了,能帮你少熬几个夜,这篇就没白写。代码我都跑过,但环境不同可能会有差异。

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 1586

【一步到位】Android Studio 实现安卓连接阿里云物联网云平台

最新版本目前是Android Studio Iguana | 2024.1.2,你可以到官网上去找之前的版本,手上有工作项目的不要去轻易尝试,说不定你就编译失败了,失败了也不要担心,解决就可以了。

m0_73799445的博客 1万+

嵌入式软件工程师面试题目整理(一)

文章目录嵌入式软件工程师面试题目整理(一)Arm有多少32位寄存器?Arm2440和6410有什么区别CPU,MPU,MCU,SOC,SOPC联系与差别上拉&下拉&高阻态串口协议讲一讲RS232和RS485通讯接口有什么区别IIC时序图画一下,IIC有哪些状态,给一个字节,将它发送出去。IIC有什么注意事项?有没有用I/O模拟IIC,如果有需要注意什么?为什么2440的内存起始地址是3后面7个0呢?为什么6410的内存起始地址是5后面7个0呢?内存管理有什么看法?(MMU)锁有哪些?有什么注

嵌入式与Linux那些事的博客 7883

Promise深度解析:前端异步编程的核心

Promise 是一个代表异步操作最终完成或失败的对象。pending:初始状态,既不是成功,也不是失败fulfilled:操作成功完成rejected:操作失败掌握 Promise 的深度原理和高级用法,能够让你在复杂的异步编程场景中游刃有余,为学习更高级的异步模式(如、RxJS 等)打下坚实基础。核心要点回顾Promise 状态不可逆.then()是微任务是链式调用的核心静态方法allraceallSettled的使用场景避免嵌套、合理使用return和。

csdn_silent的博客 1348

《RT-DETR魔术师》专栏介绍 & 优快云独家改进创新实战 & 专栏目录

通过本专栏的阅读,后续你也可以自己魔改网络,在网络不同位置(Backbone、head、neck、loss等)进行魔改,实现创新!!!

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 7372

(前端必会)理解异步和Promise的使用

1.什么是异步(asynchronization) 举个生活上的例子来说,晚餐时间到啦,我们先去煮饭,然后把饭入锅了,我们总不能一直在这里一直等到它熟了才去炒菜吧?这样多憨啊(现实中也没人会这样做吧),所以我们设置了电饭煲定时,当饭熟的时候电饭煲就会嘀嘀嘀嘀地响来通知我们。这样我们就不用在这里一直等饭熟了,煮了饭之后我们立马就去炒菜,然后菜煮好了,那边电饭煲也来通知我们饭熟了,然后我们就可以开锅了。这就是一个简单的异步流程,如果放到编程里面,就有同步任务和异步任务之分,Javascript是一个单线程的编程

weixin_43750480的博客 5042

18、未来医疗信息学中的太赫兹天线技术

本文探讨了太赫兹天线技术在医疗信息学中的关键作用,重点分析了分裂环谐振器和纳米结构光导天线(PCA)的设计与性能提升方法,介绍了相干与非相干太赫兹检测技术,并通过等效电路模型和数值模拟深入解析PCA工作机理。文章还展示了太赫兹技术在无创血糖监测、肿瘤检测等医疗诊断中的实验应用,总结了其非侵入性、高分辨率成像和多参数分析等优势,同时指出信号检测难、成本高和技术复杂等挑战。未来趋势包括设备小型化、效率提升及与人工智能融合,拓展至药物研发、皮肤与神经疾病诊断等领域,展现出变革医疗健康的巨大潜力。

milk8的博客 146

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

深入理解前端异步编程之Promise:原理、使用与最佳实践

Promise是 JavaScript 中表示异步操作最终完成或失败的对象。它可以将异步操作的结果(成功或失败)与后续处理逻辑解耦,使代码更清晰、可读性更高。特性说明状态管理三种状态(Pending、Fulfilled、Rejected),状态不可逆。链式调用通过.then()实现链式操作,解决回调地狱问题。错误处理通过.catch()或try/catch统一捕获错误。并行处理等实现多任务协作。语法糖使异步代码更接近同步写法。

web_sunn的博客 1964

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

JavaScript Promise 异步编程全解析:从基础概念到实战避坑指南

异步编程是处理网络请求、文件读写等非阻塞操作的核心技术,旨在提升应用性能和响应能力。其核心原理在于通过事件循环和任务队列管理异步任务,避免主线程阻塞。Promise 作为 ES6 引入的异步编程管理范式,提供了标准化的解决方案,其技术价值在于通过状态机(Pending、Fulfilled、Rejected)和链式调用,优雅地解决了回调地狱问题,显著提升了代码可读性和可维护性。在应用场景上,Promise 广泛应用于前端 API 调用、Node.js I/O 操作以及任何需要处理异步流程的环节。本文深入剖析

weixin_34128839的博客 844

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

40节前端高级开发进阶资料:Vue源码、NodeJS、jQ+bs、vue-cli、Vue全家桶、Promise、NodeJS、全栈SSR、金融项目前端架构实战

给国庆放放假吧~ 不,要成为一名前端高手,还是补补课吧 视频资源目录: 1、带你探究vue-router源码,实现一个基础的vue-router 2、再次探究vue源码,制作优秀的自定义插件库 3、从今天起不再懵逼-带你探究promise源码 4、探索Koa的奥秘之打造属于自己的NodeJS框架 5、实战:利用Web Components 思想组件封装 6、90分钟封装一...

javajavajava 1803

每一个前端都要学的 Promise 用法详细解析

大家好,我是若川。我持续组织了近一年的源码共读活动,感兴趣的可以点此扫码加我微信lxchuan12参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》包含20余篇源码文章。历史面试系列。另外:目前建有江西|湖南|湖北|河南籍前端群,可加我微信进群。公众号回复【相亲】关键词可以获取男生、女生的菜单~Promise是ES6之后新增的一个重要知识点(...

u012384510的博客 962
上一篇: 手写 Promise 静态方法:从原理到实现
下一篇: 什么?2025年了发版后还要手动清浏览器缓存?
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值