首页 > 编程语言 >JavaScript 事件循环与异步编程详解

JavaScript 事件循环与异步编程详解

时间:2024-12-02 17:32:35浏览次数:10  
标签:异步 resolve const JavaScript return 详解 error console await

JavaScript 事件循环与异步编程详解

1. 事件循环基础概念

JavaScript 是单线程语言,但通过事件循环(Event Loop)机制实现了异步操作。事件循环包含以下关键组件:

  • 调用栈(Call Stack)
  • 任务队列(Task Queue/Callback Queue)
  • 微任务队列(Microtask Queue)
  • Web APIs(浏览器环境)

1.1 基本运行机制

console.log('1'); // 同步任务

setTimeout(() => {
    console.log('2'); // 宏任务
}, 0);

Promise.resolve().then(() => {
    console.log('3'); // 微任务
});

console.log('4');

// 输出顺序:1, 4, 3, 2

2. 宏任务(Macrotask)和微任务(Microtask)

2.1 宏任务

  • setTimeout/setInterval
  • setImmediate (Node.js)
  • requestAnimationFrame
  • I/O
  • UI rendering

2.2 微任务

  • Promise.then/catch/finally
  • process.nextTick (Node.js)
  • MutationObserver
  • queueMicrotask()
// 宏任务和微任务的执行顺序示例
console.log('script start'); // 1

setTimeout(() => {
    console.log('setTimeout'); // 5
}, 0);

Promise.resolve()
    .then(() => {
        console.log('promise1'); // 3
    })
    .then(() => {
        console.log('promise2'); // 4
    });

console.log('script end'); // 2

// 输出顺序:
// script start
// script end
// promise1
// promise2
// setTimeout

3. Promise 详解

3.1 基本用法

const promise = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
        const random = Math.random();
        if (random > 0.5) {
            resolve('成功');
        } else {
            reject('失败');
        }
    }, 1000);
});

promise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('完成'));

3.2 Promise 链式调用

function asyncOperation(value) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value * 2);
        }, 1000);
    });
}

asyncOperation(2)
    .then(result => {
        console.log(result); // 4
        return asyncOperation(result);
    })
    .then(result => {
        console.log(result); // 8
        return asyncOperation(result);
    })
    .then(result => {
        console.log(result); // 16
    });

4. Async/Await

4.1 基本用法

async function fetchUserData() {
    try {
        const response = await fetch('https://api.example.com/user');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

4.2 并行执行

async function fetchMultipleData() {
    try {
        // 并行执行多个异步操作
        const [users, posts] = await Promise.all([
            fetch('https://api.example.com/users').then(r => r.json()),
            fetch('https://api.example.com/posts').then(r => r.json())
        ]);
        
        return { users, posts };
    } catch (error) {
        console.error('获取数据失败:', error);
        throw error;
    }
}

5. 实际应用示例

5.1 异步请求管理

class RequestManager {
    constructor() {
        this.queue = new Map();
    }

    async request(key, promiseFactory) {
        if (this.queue.has(key)) {
            return this.queue.get(key);
        }

        try {
            const promise = promiseFactory();
            this.queue.set(key, promise);
            const result = await promise;
            return result;
        } finally {
            this.queue.delete(key);
        }
    }
}

// 使用示例
const requestManager = new RequestManager();

async function fetchUserData(userId) {
    return requestManager.request(
        `user_${userId}`,
        () => fetch(`https://api.example.com/users/${userId}`).then(r => r.json())
    );
}

5.2 异步任务队列

class AsyncQueue {
    constructor() {
        this.queue = [];
        this.running = false;
    }

    async add(task) {
        return new Promise((resolve, reject) => {
            this.queue.push({ task, resolve, reject });
            this.process();
        });
    }

    async process() {
        if (this.running) return;
        this.running = true;

        while (this.queue.length > 0) {
            const { task, resolve, reject } = this.queue.shift();
            try {
                const result = await task();
                resolve(result);
            } catch (error) {
                reject(error);
            }
        }

        this.running = false;
    }
}

// 使用示例
const queue = new AsyncQueue();

async function example() {
    await queue.add(async () => {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return '任务1完成';
    });

    await queue.add(async () => {
        await new Promise(resolve => setTimeout(resolve, 500));
        return '任务2完成';
    });
}

6. 错误处理和最佳实践

6.1 错误处理

async function robustFetch(url, options = {}) {
    const MAX_RETRIES = 3;
    let lastError;

    for (let i = 0; i < MAX_RETRIES; i++) {
        try {
            const response = await fetch(url, {
                ...options,
                timeout: 5000
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            return await response.json();
        } catch (error) {
            lastError = error;
            console.warn(`Attempt ${i + 1} failed:`, error);
            await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
        }
    }

    throw lastError;
}

6.2 性能优化

// 使用 AbortController 取消请求
async function fetchWithTimeout(url, timeout = 5000) {
    const controller = new AbortController();
    const id = setTimeout(() => controller.abort(), timeout);

    try {
        const response = await fetch(url, {
            signal: controller.signal
        });
        const data = await response.json();
        return data;
    } catch (error) {
        if (error.name === 'AbortError') {
            throw new Error('Request timed out');
        }
        throw error;
    } finally {
        clearTimeout(id);
    }
}

总结

理解事件循环和异步编程对于开发高质量的 JavaScript 应用至关重要。关键点包括:

  1. 掌握宏任务和微任务的执行顺序
  2. 合理使用 Promise 和 async/await
  3. 实现可靠的错误处理机制
  4. 注意性能优化和资源管理
  5. 避免回调地狱,保持代码可读性

在实际开发中,建议:

  • 优先使用 async/await 而不是回调
  • 合理处理并发请求
  • 实现适当的超时和重试机制
  • 注意内存泄漏问题
  • 保持代码的可测试性

标签:异步,resolve,const,JavaScript,return,详解,error,console,await
From: https://blog.csdn.net/shenfangda520/article/details/144193599

相关文章

  • MongoDB索引详解
    MongoDB索引索引是一种用来快速查询数据的数据结构。B+Tree就是一种常用的数据库索引数据结构,MongoDB采用B+Tree做索引,索引创建在colletions上。MongoDB不使用索引的查询,先扫描所有的文档,再匹配符合条件的文档。使用索引的查询,通过索引找到文档,使用索引能够极大的提升查询效......
  • JavaScript操作数组
    数组的遍历、插入、删除操作在JavaScript中,数组是一种常见的数据结构,可以包含多个元素,并且可以进行遍历、插入和删除等操作。下面分别介绍数组的遍历、插入和删除操作。1,数组的判断:代码不能操作空对象(空指针),在操作数组之前,一般建议先判断数组是否为空。letarr=[1,2,3];/......
  • JavaScript操作addEventListener监听触发事件
    JavaScript的addEventListener方法允许你为指定的HTML元素添加事件监听器。以下是一些常见的事件类型,可以使用addEventListener来监听它们:1,点击事件(click)点击事件(click):当用户点击元素时触发。element.addEventListener('click',function(){console.log......
  • JavaScript操作DOM元素的classList
    在JavaScript中,classList是一个DOM元素属性,它提供了一组方法来添加、移除和切换元素的类名。classList属性返回一个DOMTokenList集合,表示元素的类名。这个集合提供了几个非常有用的方法,我们可以方便地对元素的类名进行操作,包括添加、移除、切换类名等。1,添加类名add(class1......
  • 交易系统:电商、O2O、线下门店购物流程详解
    大家好,我是汤师爷~新零售业务涉及多个销售渠道,每个渠道都有其独特的业务特点,需要相应的营销方式、运营策略和供应链管理。主要销售渠道包括:实体门店(包括直营连锁店、加盟门店)、电商平台销售(如淘宝、天猫、京东、拼多多等)、新兴流量平台(如抖音、小红书、快手等短视频平台)、本地生......
  • 一文详解阿里云可观测体系下标签最佳实践
    作者:阳其凯(逸陵)在当今数字化转型加速的时代,企业IT系统的复杂度与日俱增,如何高效地管理和监控这些系统成为了一项挑战。阿里云作为全球领先的云计算服务商,提供了一整套全面的可观测性解决方案,覆盖从业务、端侧(小程序、APP、H5等)、应用、中间件、容器/ECS等全栈的监控体系,旨在......
  • JavaWeb:Servlet详解
    该笔记根据尚硅谷的JavaWeb课程进行整理 一、Servlet简介静态资源和动态资源:(1)静态资源:无需通过代码运行生成的资源,例如:html、css、js、img,音频和视频文件(2)动态资源:需要通过代码运行生成的资源。在程序运行之前无法确定的数据,运行时动态生成,例如:Servlet、Thymeleaf......画图......
  • Android实现微信读书划线效果详解
    在移动阅读应用中,划线功能是一种非常实用的笔记和标注工具,它允许用户在阅读过程中标记出重要的内容。微信读书作为一款流行的阅读应用,其划线功能备受用户喜爱。本文将详细介绍如何在Android应用中实现类似于微信读书的划线效果。一、前期准备开发环境:AndroidStudio作为......
  • [RegCool] 64位注册表编辑器绿化免安装版下载及其使用详解(附有下载文件)
      前言RegCool链接:https://pan.quark.cn/s/e6ba3e4007ca提取码:MUrU下载下载得到压缩包解压后得到打开文件,双击.exe文件即可运行点击.exe文件得到即可使用使用示例现有一个程序,要求逆向分析程序,完成pojie使用PEiD查壳得到,程序有壳使用od找程序的入口点......
  • [VSCode] vscode下载安装及安装中文插件详解(附下载文件)
      前言vscode链接:https://pan.quark.cn/s/3acbb8aed758提取码:dSytVSCode是一款由微软开发且跨平台的免费源代码编辑器;该软件支持语法高亮、代码自动补全、代码重构、查看定义功能,并且内置了命令行工具和Git版本控制系统。通过上面的连接下载得到压缩包,解压得到exe文......