【前端教程】ES6 Promise 实战教程:从基础到游戏案例
前言
在 JavaScript 开发中,异步操作是非常常见的,比如定时器、网络请求等。而 Promise 作为 ES6 引入的异步编程解决方案,能够让我们更优雅地处理异步操作,避免"回调地狱"。
本文将通过一系列生动的实例(尤其是游戏场景),带你深入理解 Promise 的用法,包括 Promise.all()
、Promise.race()
以及 resolve
、reject
等核心概念。
异步和同步
在JavaScript和Vue开发中,同步(Synchronous)和异步(Asynchronous)是处理代码执行顺序的两种方式,它们的核心区别在于是否阻塞后续代码的执行:
1. 同步(Synchronous)
- 执行方式:代码按照顺序依次执行,前一段代码执行完毕后,才会执行下一段代码。
- 特点:会阻塞后续代码,直到当前操作完成。
- 适用场景:简单的计算、变量赋值、同步API调用等不需要等待的操作。
示例:
// 同步操作
function syncOperation() {console.log("开始同步操作");// 模拟耗时操作(同步会阻塞)for (let i = 0; i < 1000000000; i++) {}console.log("同步操作完成");
}console.log("代码开始");
syncOperation();
console.log("代码结束"); // 必须等待同步操作完成后才执行
输出顺序:
代码开始
开始同步操作
同步操作完成
代码结束
2. 异步(Asynchronous)
- 执行方式:代码不会等待当前操作完成,而是继续执行后续代码,当前操作完成后通过回调、Promise等方式通知结果。
- 特点:不会阻塞后续代码,提高程序执行效率,适合处理耗时操作。
- 适用场景:网络请求(API调用)、文件读写、定时器(
setTimeout
)等需要等待的操作。
示例(使用setTimeout
模拟异步):
// 异步操作
function asyncOperation() {console.log("开始异步操作");// 模拟耗时操作(异步不会阻塞)setTimeout(() => {console.log("异步操作完成");}, 1000);
}console.log("代码开始");
asyncOperation();
console.log("代码结束"); // 不需要等待异步操作完成
输出顺序:
代码开始
开始异步操作
代码结束
// 1秒后...
异步操作完成
3. 异步在Vue中的常见应用
在Vue组件中,异步操作非常常见,例如:
(1)网络请求(使用axios
)
export default {methods: {async fetchData() {console.log("开始请求数据");// 异步请求,不会阻塞后续代码const response = await axios.get("https://api.example.com/data");console.log("数据请求完成", response.data);}},mounted() {this.fetchData();console.log("组件挂载完成"); // 先执行,不需要等待请求完成}
};
(2)定时器操作
export default {methods: {startTimer() {console.log("定时器开始");// 1秒后执行(异步)setTimeout(() => {console.log("定时器执行完毕");}, 1000);}},created() {this.startTimer();console.log("组件创建完成"); // 先执行}
};
4. 同步与异步的核心区别
特性 | 同步操作 | 异步操作 |
---|---|---|
执行顺序 | 顺序执行,前一个完成再执行下一个 | 不等待,直接执行后续代码 |
阻塞 | 会阻塞线程 | 不会阻塞线程 |
耗时操作 | 不适合(会冻结界面) | 适合(如网络请求、文件读写) |
结果获取 | 直接返回结果 | 通过回调、Promise、async/await获取 |
总结
- 同步:简单直接,但耗时操作会阻塞程序,导致界面卡顿。
- 异步:复杂但高效,适合处理需要等待的操作,避免程序阻塞。
在Vue开发中,处理网络请求、定时器等场景时,几乎都需要使用异步方式(如async/await
、Promise
),以保证用户体验的流畅性。
什么是 Promise?
Promise 是一种用于处理异步操作的对象,它代表了一个异步操作的最终完成(或失败)及其结果值。简单来说,Promise 就是用来管理异步代码的,让异步代码的执行顺序更加可控,代码结构更加清晰。
个人理解:当代码中出现了异步操作(setTimeout、ajax、setInterval),而且需要对这些操作的执行顺序进行控制时,就应该使用 Promise。Promise 能让代码看起来更"优雅"。
基础概念
- resolve:异步操作成功时调用的函数,将 Promise 状态改为成功
- reject:异步操作失败时调用的函数,将 Promise 状态改为失败
- then:用于指定 Promise 状态改变时的回调函数
- catch:用于捕获 Promise 执行过程中的错误
- Promise.all():等待所有 Promise 完成后再执行
- Promise.race():只要有一个 Promise 完成就执行(竞赛机制)
定时器小知识
setTimeout
:设定特定时间后执行一次函数setInterval
:每隔特定时间重复执行函数
实战案例
案例 1:游戏任务完成后升级(Promise.all())
在一个游戏中,有两个任务:采蘑菇和杀鸡。要求两个任务都完成以后才能升级。
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>游戏任务升级</title>
</head>
<body><script>// 采蘑菇任务function pickMushrooms() {return new Promise(function(resolve, reject) {setTimeout(function() {console.log('采蘑菇任务完成');resolve('采蘑菇'); // 传递任务结果}, 2333); // 2.333秒完成});}// 杀鸡任务function killChicken() {return new Promise(function(resolve, reject) {setTimeout(function() {console.log('杀鸡任务完成');resolve('杀鸡'); // 传递任务结果}, 6666); // 6.666秒完成});}// 执行两个任务let task1 = pickMushrooms();let task2 = killChicken();// 等待所有任务完成后升级Promise.all([task1, task2]).then(function(results