当前位置: 首页 > news >正文

promise和异步编程

一、Promise 的使用场景及实现方法

Promise 是一种用于处理异步操作的解决方案,能够有效地避免回调地狱(Callback Hell),使代码更加清晰、易于维护。在前端开发中,Promise 的主要使用场景包括但不限于以下几种:

  • 异步数据请求:如通过 AJAX 获取远程数据。
  • 文件读写操作:例如在浏览器环境中读取本地文件。
  • 定时器任务:延迟执行某些逻辑或等待特定时间后触发事件。
  • 动画控制:等待动画完成后再执行后续操作。

二、Promise 的基本用法

Promise 对象表示一个异步操作的最终完成(或失败)及其结果值。它有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise 的核心方法包括 thencatch,分别用于处理成功和失败的情况。此外,还可以结合 async/await 语法来简化异步代码的书写。

// 创建一个 Promise 实例
const myPromise = new Promise((resolve, reject) => {setTimeout(() => {const success = true; // 模拟异步操作的结果if (success) {resolve("操作成功");} else {reject("操作失败");}}, 1000);
});// 使用 then 和 catch 处理 Promise
myPromise.then(result => console.log(result)) // 输出: 操作成功.catch(error => console.error(error)); // 如果失败会输出错误信息

三、Vue 3 中的 Promise 示例

在 Vue 3 中,可以结合 setup 函数或者生命周期钩子(如 mounted)来处理异步操作。以下是一个使用 Axios 发起 HTTP 请求并处理 Promise 的示例:

<template><div><p v-if="loading">加载中...</p><p v-else>{{ data }}</p></div>
</template><script>
import { ref } from 'vue';
import axios from 'axios';export default {setup() {const data = ref(null);const loading = ref(true);const fetchData = async () => {try {const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');data.value = response.data.title;} catch (error) {console.error('数据获取失败:', error);} finally {loading.value = false;}};fetchData();return { data, loading };}
};
</script>

上述代码展示了如何在 Vue 3 的 setup 函数中使用 async/await 来处理 Promise,并将异步数据绑定到模板中显示。

四、Promise 的实现方式

Promise 的实现依赖于 JavaScript 的事件循环机制。当创建一个新的 Promise 时,其内部的执行函数会立即运行,而 resolvereject 的回调会被放入微任务队列中,等待当前宏任务完成后执行。以下是 Promise 的简单实现示例:

class MyPromise {constructor(executor) {this.state = 'pending'; // 初始状态为 pendingthis.value = undefined; // 成功的值this.reason = undefined; // 失败的原因this.onResolveCallbacks = []; // 存储成功的回调this.onRejectCallbacks = []; // 存储失败的回调const resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;this.onResolveCallbacks.forEach(callback => callback());}};const reject = reason => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.onRejectCallbacks.forEach(callback => callback());}};try {executor(resolve, reject);} catch (error) {reject(error);}}then(onFulfilled, onRejected) {if (this.state === 'fulfilled') {onFulfilled(this.value);}if (this.state === 'rejected') {onRejected(this.reason);}if (this.state === 'pending') {this.onResolveCallbacks.push(() => onFulfilled(this.value));this.onRejectCallbacks.push(() => onRejected(this.reason));}}
}

五、Promise 静态方法列表

Promise 提供了多个静态方法,用于简化异步操作的处理。以下是 Promise 的静态方法列表及其功能描述:

  1. Promise.resolve(value)
    该方法返回一个以给定值解析后的 Promise 对象。如果传入的是一个 thenable 对象(即具有 then 方法的对象),则返回的 Promise 会“跟随”这个 thenable 对象,采用它的最终状态;如果传入的已经是 Promise,则直接返回这个 Promise。

    Promise.resolve("string").then(function(value) {console.log(value); // "string"
    });
    
  2. Promise.reject(reason)
    该方法返回一个带有拒绝原因的 Promise 对象。它不会捕获错误,因此通常需要配合 .catch() 使用以处理拒绝的情况。

    Promise.reject("error").catch(function(reason) {console.log(reason); // "error"
    });
    
  3. Promise.all(iterable)
    该方法接受一个可迭代对象(如数组)作为参数,并返回一个新的 Promise 实例。只有当 iterable 中的所有 Promise 都成功时,返回的 Promise 才会成功,并将所有结果按顺序放入一个数组中。如果任意一个 Promise 失败,则返回的 Promise 会立即失败,并返回第一个失败的原因。

    Promise.all([Promise.resolve(1), Promise.resolve(2)]).then(function(values) {console.log(values); // [1, 2]
    });
    
  4. Promise.any(iterable)
    该方法接受一个可迭代对象作为参数,并返回一个新的 Promise 实例。只要 iterable 中有一个 Promise 成功,返回的 Promise 就会成功,并返回第一个成功的值。如果所有 Promise 都失败,则返回的 Promise 会失败,并抛出一个 AggregateError 错误。

    Promise.any([Promise.reject(1), Promise.resolve(2)]).then(function(value) {console.log(value); // 2
    });
    
  5. Promise.race(iterable)
    该方法接受一个可迭代对象作为参数,并返回一个新的 Promise 实例。一旦 iterable 中的某个 Promise 变成已决状态(无论是成功还是失败),返回的 Promise 就会立即变成相同的状态。

    Promise.race([Promise.resolve(1), Promise.resolve(2)]).then(function(value) {console.log(value); // 1
    });
    
  6. Promise.allSettled(iterable)
    该方法接受一个可迭代对象作为参数,并返回一个新的 Promise 实例。无论 iterable 中的 Promise 最终是成功还是失败,返回的 Promise 都会成功,并返回一个包含每个 Promise 状态和结果的数组。

    Promise.allSettled([Promise.resolve(1), Promise.reject(2)]).then(function(results) {console.log(results);// [{ status: "fulfilled", value: 1 }, { status: "rejected", reason: 2 }]
    });
    

注意事项

  • Promise.allPromise.any 的行为不同:前者要求所有 Promise 都成功,而后者只需要一个成功即可。
  • Promise.race 是最敏感的方法,因为它会立即响应第一个已决的 Promise。
  • Promise.allSettled 是 ES2020 引入的新方法,确保所有 Promise 都被处理,无论其状态如何。

六、Promise与Async/Await的区别及用法对比

1、Async/Await的基本概念及作用

Async/Await 是基于 Promise 的语法糖,提供了一种更简洁的方式来处理异步代码。async 关键字用于声明一个函数为异步函数,而 await 关键字则用于等待一个 Promise 的完成。使用 Async/Await 可以让异步代码看起来像同步代码,从而提高代码的可读性和可维护性。

async function fetchData() {try {const result = await someAsyncFunction(); // 等待异步操作完成console.log(result);} catch (error) {console.error(error); // 捕获并处理错误}
}
2、、Promise与Async/Await的用法对比
  1. 链式调用 vs 简洁语法
    使用 Promise 时,通常需要通过 .then().catch() 方法进行链式调用来处理异步操作的结果。而 Async/Await 则通过 await 关键字直接获取 Promise 的结果,避免了回调地狱的问题。

  2. 错误处理
    在 Promise 中,错误处理通常通过 .catch() 方法实现。而在 Async/Await 中,可以使用 try...catch 语句来捕获和处理错误,这种方式更接近于同步代码中的错误处理方式。

  3. 多任务处理
    当需要同时处理多个异步任务时,Promise 提供了如 Promise.all()Promise.race() 等静态方法。而 Async/Await 则需要结合这些方法来实现类似的功能。

// 使用 Promise.all()
Promise.all([promise1, promise2, promise3]).then(results => {console.log(results);
}).catch(error => {console.error(error);
});// 使用 Async/Await 结合 Promise.all()
async function fetchAllData() {try {const results = await Promise.all([promise1, promise2, promise3]);console.log(results);} catch (error) {console.error(error);}
}
3、Async/Await比Promise优越的表现

Async/Await 的主要优势在于其语法更加简洁,代码结构更接近同步代码,减少了嵌套层级,提高了代码的可读性。此外,使用 try...catch 进行错误处理也更加直观。

4、总结

Promise 和 Async/Await 都是 JavaScript 中处理异步操作的重要工具。Promise 提供了灵活的链式调用和多种静态方法,适用于复杂的多任务场景。而 Async/Await 则通过简化语法和增强可读性,成为处理单个异步任务的首选方案。

七、JavaScript 事件循环、宏任务与微任务的工作原理

1. 单线程与事件循环

JavaScript 是单线程语言,这意味着它在同一时间只能执行一个任务。然而,通过事件循环(Event Loop)机制,JavaScript 能够处理异步操作,从而实现看似多线程的效果。事件循环的核心在于将任务分为宏任务(MacroTask)和微任务(MicroTask),并按照特定的顺序执行它们。

2. 宏任务与微任务的区别

宏任务和微任务是事件循环中的两种任务类型。宏任务包括整体代码块、setTimeoutsetIntervalsetImmediate 等。微任务则包括 Promise.thenMutationObserverprocess.nextTick(Node.js 中)等。

  • 宏任务:每次执行完一个宏任务后,会检查是否有微任务需要执行。只有当所有微任务执行完毕后,才会继续执行下一个宏任务。
  • 微任务:优先于宏任务执行。即使有多个微任务,也会在当前宏任务结束后立即依次执行。
3. 事件循环的工作流程

事件循环的基本工作流程如下:

  1. 执行栈中的同步代码。
  2. 遇到异步代码时,将其对应的回调函数放入相应的任务队列中(宏任务或微任务队列)。
  3. 每次完成一个宏任务后,检查微任务队列,依次执行其中的所有微任务。
  4. 继续从宏任务队列中取出下一个任务,重复上述过程。
console.log('Script start'); // 同步代码setTimeout(() => {console.log('MacroTask 1');
}, 0);Promise.resolve().then(() => {console.log('MicroTask 1');
});console.log('Script end'); // 同步代码

输出结果为:

Script start
Script end
MicroTask 1
MacroTask 1

解释:

  • console.log('Script start')console.log('Script end') 是同步代码,直接执行。
  • Promise.resolve().then() 创建了一个微任务,会在当前宏任务完成后立即执行。
  • setTimeout 创建了一个宏任务,需等待所有微任务执行完毕后才会执行。
4. Promise 与事件循环的关系

Promise 是一种用于处理异步操作的对象,其 .then() 方法会将回调函数放入微任务队列中。因此,Promise 的回调函数总是比宏任务优先执行。

setTimeout(() => {console.log('MacroTask');
}, 0);Promise.resolve().then(() => {console.log('MicroTask');
});console.log('Sync Code');

输出结果为:

Sync Code
MicroTask
MacroTask
5. 异步编程与事件循环

异步编程的核心在于合理利用宏任务和微任务的执行顺序。通过将任务分配到不同的队列中,可以优化程序的性能和响应速度。例如,使用 Promise 可以避免回调地狱问题,而 async/await 则进一步简化了异步代码的编写。

async function example() {console.log('Async Function Start');await new Promise(resolve => setTimeout(() => resolve('Resolved'), 0));console.log('Async Function End');
}example();
console.log('Global Code');

输出结果为:

Async Function Start
Global Code
Async Function End

解释:

  • console.log('Async Function Start') 是同步代码,直接执行。
  • await 会暂停函数的执行,直到 Promise 被解决。
  • console.log('Global Code') 是全局代码,不依赖任何异步操作,因此在 await 暂停期间执行。
  • 最后,console.log('Async Function End') 在 Promise 被解决后执行。
6.总结

事件循环是 JavaScript 异步编程的核心机制,通过将任务分为宏任务和微任务,并按照特定的顺序执行,确保了程序的高效运行。Promise 和 async/await 是基于事件循环的异步编程工具,能够显著提升代码的可读性和维护性。

http://www.xdnf.cn/news/875089.html

相关文章:

  • Java框架面试题
  • (1-6-3)Java 多线程
  • iptables实战案例
  • STM32最小CLion开发环境
  • L2-056 被n整除的n位数 - java
  • Docker慢慢学
  • unity+ spine切换武器不换皮肤解决方案
  • C#Winform中DevExpress下的datagridview 特定列可编辑,其他列不可编辑
  • “详规一张图”——香港土地利用数据
  • java.sql.BatchUpdateException: Incorrect string value: ‘\xF0\x9F\x91\x91**...‘
  • 面试题小结(真实面试)
  • Java编程常见错误与最佳实践
  • machine_env_loader must have been assigned before creating ssh child instance
  • hadoop集群启动没有datanode解决
  • PyCharm项目和文件运行时使用conda环境的教程
  • Python趣学篇:用数学方程绘制浪漫爱心
  • SpringBoot+Mybatisplus配置多数据源(超级简单!!!!)
  • #Java篇:学习node后端之sql常用操作
  • BBU 电源市场报告:深入剖析与未来展望​
  • 洛谷P1591阶乘数码
  • GO语言---函数命名返回值
  • 嵌入式系统中常用的开源协议
  • 41、响应处理-【源码分析】-自定义MessageConverter
  • [C]深入解析条件式日志宏的设计原理
  • Deepfashion2 数据集使用笔记
  • 2025年五一数学建模竞赛A题-支路车流量推测问题详细建模与源代码编写(一)
  • 洛谷 单源最短路径 Dijkstra算法+优先队列
  • 点云数据去噪(Point Cloud Processing Toolbox)
  • C++——智能指针 shared_ptr
  • 小黑黑日常积累:dataclass的简单使用