各位观众老爷们,掌声欢迎来到今天的Promise专场!我是你们的老朋友,码农张三,今天咱们不聊妹子,不聊八卦,就聊聊这Promise,这玩意儿,用好了,那是异步操作的丝滑小棉袄,用不好,那就是让你debug到怀疑人生的罪魁祸首。
准备好了吗?Let’s dive in!
第一章:Promise,你到底是个什么玩意儿?
首先,咱们得搞清楚Promise这东西到底是个什么来头。 你可以把它想象成一个承诺,承诺将来会给你一个结果,这个结果可能是成功(resolve),也可能是失败(reject)。 在这结果出来之前,Promise的状态是 pending(等待)。
举个例子,你去饭店点了个菜,服务员说:“您稍等,这菜得现做。” 这就是Promise的 pending 状态。 你也不知道这菜啥时候能上,也不知道做出来好不好吃。
如果菜做好了,端上来了,而且很好吃,那就是 resolve(成功) 了,你吃得心满意足。
如果菜做砸了,糊了,或者根本没材料了,那就是 reject(失败) 了,你只能换个菜或者饿肚子。
所以,Promise 就是一个代表异步操作最终完成(或失败)的一个对象。
第二章:Promise 的三种状态
Promise 有三种状态,这是理解 Promise 的基础:
状态 | 描述 |
---|---|
pending | 初始状态,既不是成功也不是失败。 就像你刚点完菜,厨师还没开始做,你也不知道会发生什么。 |
fulfilled | 操作成功完成。 菜做好了,端上来了,而且很好吃。 对应 resolve() 方法 |
rejected | 操作失败。 菜做砸了,或者根本没材料了。 对应 reject() 方法 |
注意:Promise 的状态一旦改变,就不会再变了。 也就是说,一个 Promise 要么 resolve,要么 reject,不会出现一会儿成功一会儿失败的情况。 这就像你点的菜,要么做好了,要么做砸了,不可能一会儿好吃一会儿难吃,除非你点的菜是薛定谔的菜。
第三章:创建 Promise:new Promise()
要使用 Promise,首先要创建一个 Promise 对象。 创建 Promise 对象很简单,使用 new Promise()
构造函数:
const myPromise = new Promise((resolve, reject) => {
// 这里放你的异步操作,比如网络请求、定时器等等
// 如果操作成功,调用 resolve(),并将结果作为参数传递进去
// 例如:
// resolve('菜做好了,好吃!');
// 如果操作失败,调用 reject(),并将错误信息作为参数传递进去
// 例如:
// reject('菜做砸了!');
});
new Promise()
构造函数接收一个函数作为参数,这个函数被称为 executor(执行器)。 executor 函数接收两个参数:resolve
和 reject
,它们都是函数。
resolve(value)
:将 Promise 的状态改为 fulfilled,并将 value 作为结果传递给后续的then()
方法。reject(reason)
:将 Promise 的状态改为 rejected,并将 reason 作为错误信息传递给后续的catch()
方法。
第四章:处理 Promise 的结果:.then() 和 .catch()
创建了 Promise 对象之后,我们需要处理 Promise 的结果。 这就要用到 .then()
和 .catch()
方法了。
-
.then(onFulfilled, onRejected)
:用于处理 Promise 成功(fulfilled)的情况。 它接收两个参数:onFulfilled
和onRejected
,都是函数。onFulfilled
在 Promise 成功时被调用,接收 Promise 的结果作为参数。onRejected
在 Promise 失败时被调用,接收 Promise 的错误信息作为参数。onRejected
可以省略,不建议省略,容易造成错误被忽略的情况。 -
.catch(onRejected)
:用于处理 Promise 失败(rejected)的情况。 它接收一个参数:onRejected
,是一个函数。onRejected
在 Promise 失败时被调用,接收 Promise 的错误信息作为参数。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(`成功啦!随机数是:${randomNumber}`);
} else {
reject(`失败啦!随机数是:${randomNumber}`);
}
}, 1000); // 模拟一个 1 秒的异步操作
});
myPromise
.then(
(result) => {
console.log('Promise 成功了:', result);
},
(error) => {
console.error('Promise 失败了(在then中处理):', error);
}
)
.catch((error) => {
console.error('Promise 失败了(在catch中处理):', error);
});
console.log("代码继续执行,不会阻塞!");
在这个例子中,我们创建了一个 Promise 对象,它会在 1 秒后随机 resolve 或 reject。 如果随机数大于 0.5,Promise 就 resolve,否则就 reject。
我们使用 .then()
方法来处理 Promise 成功和失败的情况。 同时我们也使用了.catch()
方法来捕获异常,注意这里.then()
的第二个参数和.catch()
作用一样,但是推荐使用.catch()
,便于阅读和维护。
第五章:Promise 链:优雅地处理多个异步操作
Promise 最强大的地方在于它可以链式调用 .then()
方法,从而优雅地处理多个异步操作。
const fetchUserData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const userData = { id: 123, name: '张三' };
resolve(userData);
}, 500);
});
};
const fetchUserPosts = (userId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const userPosts = [
{ id: 1, title: 'Promise 入门' },
{ id: 2, title: 'Async/Await 进阶' },
];
resolve(userPosts);
}, 500);
});
};
fetchUserData()
.then((userData) => {
console.log('获取到用户信息:', userData);
return fetchUserPosts(userData.id); // 返回一个新的 Promise
})
.then((userPosts) => {
console.log('获取到用户文章:', userPosts);
})
.catch((error) => {
console.error('出错了:', error);
});
在这个例子中,我们先使用 fetchUserData()
函数获取用户信息,然后使用 fetchUserPosts()
函数获取用户的文章。 每个 .then()
方法都返回一个新的 Promise,这样就可以将多个异步操作串联起来。 这种链式调用使得代码更加清晰易懂,也更容易维护。
第六章:Promise.all():并行处理多个异步操作
有时候,我们需要同时执行多个异步操作,并且在所有操作都完成后再进行下一步处理。 这时候就可以使用 Promise.all()
方法。
Promise.all()
接收一个 Promise 数组作为参数,返回一个新的 Promise。 这个新的 Promise 会在所有 Promise 都 resolve 时 resolve,并将所有 Promise 的结果以数组的形式返回。 如果其中任何一个 Promise reject,这个新的 Promise 就会立即 reject,并将 reject 的原因返回。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise 1 完成');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise 2 完成');
}, 500);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise 3 完成');
}, 1500);
});
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log('所有 Promise 都完成了:', results); // 输出:['Promise 1 完成', 'Promise 2 完成', 'Promise 3 完成']
})
.catch((error) => {
console.error('有 Promise 失败了:', error);
});
在这个例子中,我们创建了三个 Promise 对象,它们分别在 1 秒、0.5 秒和 1.5 秒后 resolve。 Promise.all()
会等待所有 Promise 都 resolve 后,才执行 .then()
方法。
第七章:Promise.race():赛跑模式
Promise.race()
方法与 Promise.all()
类似,也接收一个 Promise 数组作为参数,返回一个新的 Promise。 但是,Promise.race()
的行为却截然不同。
Promise.race()
返回的 Promise 会在第一个 Promise resolve 或 reject 时立即 resolve 或 reject,并将第一个 Promise 的结果或错误信息返回。 也就是说,Promise.race()
就像一场赛跑,谁先跑完,就算谁赢。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Promise 1 完成');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('Promise 2 失败');
}, 500);
});
Promise.race([promise1, promise2])
.then((result) => {
console.log('第一个完成的 Promise 是:', result); // 不会执行到这里,因为 promise2 失败了
})
.catch((error) => {
console.error('第一个失败的 Promise 是:', error); // 输出:'第一个失败的 Promise 是:Promise 2 失败'
});
在这个例子中,promise2
在 0.5 秒后 reject,所以 Promise.race()
会立即 reject,并将 promise2
的错误信息返回。
第八章:Promise 的一些小技巧
-
使用
Promise.resolve()
和Promise.reject()
快速创建已完成或已失败的 Promise。const resolvedPromise = Promise.resolve('立即完成!'); const rejectedPromise = Promise.reject('立即失败!'); resolvedPromise.then(result => console.log(result)); // 输出:'立即完成!' rejectedPromise.catch(error => console.error(error)); // 输出:'立即失败!'
-
避免在 executor 函数中直接返回值。 应该使用
resolve()
或reject()
来改变 Promise 的状态。// 错误示例: const badPromise = new Promise((resolve, reject) => { return '错误的值'; // 这样写不会改变 Promise 的状态 }); badPromise.then(result => console.log(result)); // 不会执行到这里 // 正确示例: const goodPromise = new Promise((resolve, reject) => { resolve('正确的值'); // 这样写会改变 Promise 的状态 }); goodPromise.then(result => console.log(result)); // 输出:'正确的值'
-
使用
finally()
方法在 Promise 完成后执行一些清理工作,无论 Promise 是 resolve 还是 reject。const myPromise = new Promise((resolve, reject) => { setTimeout(() => { Math.random() > 0.5 ? resolve('成功') : reject('失败'); }, 500); }); myPromise .then(result => console.log(result)) .catch(error => console.error(error)) .finally(() => { console.log('无论成功还是失败,都会执行这里'); });
第九章:Promise 与 Async/Await:更优雅的异步语法糖
Async/Await 是 ES2017 引入的,用于简化异步操作的语法糖。 它可以让你像写同步代码一样写异步代码,大大提高了代码的可读性和可维护性。
Async/Await 实际上是基于 Promise 实现的,所以理解 Promise 是理解 Async/Await 的基础。
-
async
函数: 在函数声明前加上async
关键字,表示这是一个异步函数。 async 函数会自动返回一个 Promise 对象。 -
await
表达式: 在 async 函数中使用await
关键字,可以暂停函数的执行,等待 Promise resolve。await
表达式会返回 Promise 的结果。
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await response.json();
console.log('获取到的数据:', data);
return data;
} catch (error) {
console.error('出错了:', error);
throw error; // 重新抛出错误,方便外部捕获
}
};
fetchData()
.then(data => console.log('最终的数据:', data))
.catch(error => console.error('外部捕获的错误:', error));
在这个例子中,我们使用 async
关键字声明了一个异步函数 fetchData()
。 在 fetchData()
函数中,我们使用 await
关键字等待 fetch()
和 response.json()
方法返回的 Promise resolve。 try...catch
块用于捕获异步操作中的错误。
Async/Await 使得异步代码更加简洁易懂,也更容易调试。
第十章:总结:Promise,异步世界的瑞士军刀
Promise 是 JavaScript 中处理异步操作的重要工具。 它可以让你更优雅地管理异步操作,避免回调地狱,提高代码的可读性和可维护性。
掌握 Promise 的基础知识,包括 Promise 的三种状态、.then()
和 .catch()
方法、Promise 链、Promise.all()
和 Promise.race()
方法,以及 Async/Await 语法糖,你就可以在异步世界里游刃有余,写出更加健壮和高效的代码。
记住,熟能生巧,多练习,多实践,你也能成为 Promise 大师!
今天的Promise讲座就到这里,感谢大家的聆听,下课! 别忘了点个赞再走哦!