27 JavaScript学习:异步编程

异步的概念

在JavaScript中,异步编程是一项重要的概念,特别在处理用户交互、网络请求和文件读写等场景下非常常见。JavaScript是一门单线程语言,因此需要通过异步编程来避免阻塞主线程,保证程序的流畅性和响应性。
在这里插入图片描述

在JavaScript中实现异步编程有几种方式:

  1. 回调函数(Callbacks): 回调函数是最基本的异步编程模式,通过在一个函数执行完毕后调用另一个函数来处理结果。例如,在Ajax请求中经常使用回调函数来处理服务器端的响应。

  2. Promise: Promise是ES6引入的一种处理异步操作的方法。使用Promise可以更清晰地表达异步操作的结果,并且可以链式调用多个操作。

  3. Async/Await: Async/Await是ES8引入的语法糖,用于简化Promise的操作。通过async关键字定义的函数可以使用await关键字等待异步操作的结果,使代码看起来更加同步。

  4. 事件监听(Event listeners): 通过事件监听器可以实现订阅发布模式,当某个事件发生时再执行相应的操作。这种模式在处理用户交互或者计时器等场景下非常有用。

  5. Generator函数: Generator函数也可以实现异步操作,通过yield关键字可以暂停函数的执行,然后通过.next()方法继续执行。结合Promise可以完成复杂的异步操作。

总的来说,在JavaScript中实现异步操作是为了避免阻塞主线程,提高程序的性能和响应速度。不同的异步编程方式适用于不同的场景,开发者可以根据具体需求来选择适合的方法。

异步使用场景

JavaScript中异步编程的常见使用场景包括:

  1. 网络请求: 在进行Ajax、Fetch等网络请求时,需要使用异步操作来处理响应,否则主线程将被阻塞。

  2. 文件I/O: 读写文件是一种耗时的操作,使用异步I/O可以避免阻塞主线程。

  3. 定时器: 使用setTimeout和setInterval等函数实现的定时器是异步的,它们不会阻塞主线程的执行。

  4. 事件处理: 在处理用户交互事件(点击、滚动、键盘输入等)时,需要使用事件监听的异步方式。

  5. 数据流处理: 流式数据处理(如视频、音频)通常使用异步的方式来处理数据块,以保证程序的响应性。

  6. 任务队列: 在Web Worker或Node.js中,可以把耗时的任务放到任务队列中异步执行,减轻主线程负担。

  7. 消息队列: 消息队列是一种常见的异步通信机制,用于解耦不同服务或模块之间的依赖关系。

  8. 数据库操作: 与数据库的交互通常是异步进行的,以免阻塞主线程。

  9. 机器学习/数据分析: 复杂的计算任务可以采用异步方式执行,避免影响用户体验。

总的来说,异步编程是JavaScript应对I/O密集型任务的重要手段,可以大幅提高程序的性能和响应能力。合理利用异步机制是编写高质量JavaScript应用程序的关键所在。

回调函数

回调函数是一种常见的异步编程模式,在JavaScript中被广泛使用。回调函数本质上是一个函数,作为参数传递给另一个函数,当特定事件发生或者异步操作完成时,这个回调函数会被执行。

以下是回调函数的一些重要特点和使用场景:

特点:

  1. 异步操作处理: 回调函数通常用于处理异步操作的结果,例如Ajax请求、定时器等。
  2. 事件处理: 在事件监听器中,通常也会使用回调函数来处理特定事件的触发。
  3. 数据传递: 回调函数可以接收参数,用来传递数据给回调函数进行处理。

使用场景:

  1. Ajax请求:

    function fetchData(callback) {
        // 模拟Ajax请求
        setTimeout(() => {
            const data = 'Some data';
            callback(data);
        }, 1000);
    }
    
    fetchData((data) => {
        console.log('Data received:', data);
    });
    
  2. 事件处理:

    document.getElementById('myButton').addEventListener('click', () => {
        console.log('Button clicked');
    });
    
  3. 定时器:

    setTimeout(() => {
       console.log('Timeout executed');
    }, 2000);
    
  4. Node.js中的文件I/O:

    const fs = require('fs');
    
    fs.readFile('data.txt', 'utf8', (err, data) => {
        if (err) throw err;
        console.log(data);
    });
    

回调函数是一种灵活且强大的工具,能够帮助处理各种异步操作和事件。然而,过多的回调函数嵌套容易导致"回调地狱",不利于代码的维护和阅读。因此,后续的Promise、Async/Await等方式的出现也是为了解决这一问题。

异步Ajax

在这里插入图片描述

异步Ajax是一种常见的前端编程技术,用于在网页中发送异步请求并处理响应,而不会阻塞页面的加载和用户交互。通过回调函数,可以在Ajax请求完成后执行特定的操作。

下面是一个使用回调函数处理异步Ajax请求的示例:

function fetchData(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status === 200) {
                // 请求成功,调用回调函数并传递响应数据
                callback(null, xhr.responseText);
            } else {
                // 请求失败,调用回调函数并传递错误信息
                callback(new Error('Ajax request failed'));
            }
        }
    };
    xhr.open('GET', url, true);
    xhr.send();
}

// 调用fetchData函数并传入回调函数处理响应
fetchData('https://api.example.com/data', function(err, data) {
    if (err) {
        console.error('Error:', err.message);
    } else {
        console.log('Data received:', data);
    }
});

在这个例子中,fetchData函数接受一个URL和一个回调函数作为参数。当Ajax请求完成后,回调函数会被调用,根据请求的结果执行相应的操作。如果请求成功,回调函数会将错误参数设为null,并传递响应数据;如果请求失败,回调函数会将错误信息传递给第一个参数,并将数据参数设为undefined。

Promise

Promise是一种用于处理JavaScript异步操作的对象,它代表了一个异步操作的最终完成或失败,并返回相应的结果。Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。一旦Promise状态发生改变,就会执行相应的回调函数。

使用Promise可以改善回调地狱(callback hell)问题,使代码更易读、更可维护。Promise提供了链式调用的方式来处理异步操作,避免了深层嵌套的回调函数。

一个简单的Promise示例如下:

// 创建一个Promise对象
let myPromise = new Promise((resolve, reject) => {
    // 异步操作,例如Ajax请求
    setTimeout(() => {
        let data = 'Promise resolved data';
        if (data) {
            resolve(data); // 异步操作成功,调用resolve并传递数据
        } else {
            reject('Promise rejected'); // 异步操作失败,调用reject并传递错误信息
        }
    }, 2000);
});

// 处理Promise对象的状态
myPromise.then((data) => {
    console.log('Promise resolved:', data); // 异步操作成功
}).catch((error) => {
    console.error('Promise rejected:', error); // 异步操作失败
});

在上面的示例中,首先创建了一个Promise对象myPromise,在Promise的executor函数中进行了一个模拟的异步操作,并根据操作结果调用resolvereject方法。接着通过.then()方法处理异步操作成功的情况,通过.catch()方法处理异步操作失败的情况。这样可以清晰地表示异步操作的成功和失败,并链式调用不同的操作。

Promise 的构造函数

Promise构造函数是Promise的一个内置属性,用于创建一个新的Promise对象。它接受一个参数,这个参数是一个函数,也称为"executor"。

Promise构造函数的语法如下:

new Promise(executor);

其中,executor是一个函数,它接受两个参数resolvereject,分别是两个回调函数,用于改变Promise对象的状态。

下面是一个简单的例子:

// 创建一个Promise对象
let myPromise = new Promise((resolve, reject) => {
    // 异步操作
    if (/* 异步操作成功 */) {
        resolve('操作成功'); // 使用resolve改变Promise对象的状态为fulfilled
    } else {
        reject('操作失败'); // 使用reject改变Promise对象的状态为rejected
    }
});

在上面的例子中,executor函数中包含了一个异步操作,根据操作的结果调用resolvereject来改变Promise对象的状态。如果异步操作成功,则调用resolve方法并传递操作成功的结果;如果异步操作失败,则调用reject方法并传递错误信息。

需要注意的是,executor函数在创建Promise对象时立即执行,并且只会执行一次。在executor函数中进行的异步操作可能需要一些时间来完成,而Promise则会立即返回一个pending状态的对象,并在异步操作完成后改变状态。

Promise 使用

当然,下面是一个使用Promise的综合示例列表:

  1. 基本示例:创建一个简单的Promise对象,根据条件决定是解决还是拒绝Promise。
const myPromise = new Promise((resolve, reject) => {
    const condition = true;
    
    if (condition) {
        resolve("操作成功");
    } else {
        reject("操作失败");
    }
});

myPromise.then((message) => {
    console.log(message);
}).catch((error) => {
    console.error(error);
});
  1. 异步示例:模拟一个异步操作,并使用Promise来处理成功和失败的情况。
const asyncOperation = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;
            if (success) {
                resolve("异步操作成功");
            } else {
                reject("异步操作失败");
            }
        }, 2000);
    });
};

asyncOperation().then((message) => {
    console.log(message);
}).catch((error) => {
    console.error(error);
});
  1. Promise链:使用Promise链来依次执行多个异步操作。
const firstAsyncOperation = () => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("第一个异步操作完成");
        }, 1000);
    });
};

const secondAsyncOperation = () => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("第二个异步操作完成");
        }, 1500);
    });
};

firstAsyncOperation()
    .then((message) => {
        console.log(message);
        return secondAsyncOperation();
    })
    .then((message) => {
        console.log(message);
    });

这些是一些简单的Promise示例,展示了如何创建、使用和组合Promise对象来处理异步操作。

回答常见的问题(FAQ)

Q: then、catch 和 finally 序列能否顺序颠倒?

A: 可以,效果完全一样。但不建议这样做,最好按 then-catch-finally 的顺序编写程序。

Q: 除了 then 块以外,其它两种块能否多次使用?

A: 可以,finally 与 then 一样会按顺序执行,但是 catch 块只会执行第一个,除非 catch 块里有异常。所以最好只安排一个 catch 和 finally 块。

Q: then 块如何中断?

A: then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。

Q: 什么时候适合用 Promise 而不是传统回调函数?

A: 当需要多次顺序执行异步操作的时候,例如,如果想通过异步方法先后检测用户名和密码,需要先异步检测用户名,然后再异步检测密码的情况下就很适合 Promise。

Q: Promise 是一种将异步转换为同步的方法吗?

A: 完全不是。Promise 只不过是一种更良好的编程风格。

Q: 什么时候我们需要再写一个 then 而不是在当前的 then 接着编程?

A: 当你又需要调用一个异步任务的时候。

异步函数

在JavaScript中,异步函数可以通过asyncawait关键字来定义和使用。异步函数通常与Promise对象结合使用,以便处理异步操作并获取结果。下面我将详细解释异步函数的用法,并举例说明。

异步函数的定义

在JavaScript中,使用async关键字定义一个异步函数。异步函数可以包含异步操作,并在需要时暂停执行并等待结果。例如:

async function fetchData() {
    return fetch('https://api.example.com/data');
}

异步函数的调用

要调用异步函数并等待其结果,可以使用await关键字。await只能在异步函数内部使用,用于暂停函数的执行直到异步操作完成并返回结果。例如:

async function displayData() {
    const response = await fetchData();
    const data = await response.json();
    console.log(data);
}

displayData();

异步函数的错误处理

异步函数中发生的错误可以通过try...catch语句捕获和处理。例如:

async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error fetching data:', error);
    }
}
fetchData();

示例:

下面是一个简单的示例,演示了如何使用异步函数从API获取数据并显示在页面上:

async function fetchData() {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
}

async function displayData() {
    try {
        const data = await fetchData();
        document.getElementById('result').innerText = JSON.stringify(data);
    } catch (error) {
        console.error('Error fetching and displaying data:', error);
    }
}

displayData();

以上就是JavaScript中异步函数的概念、定义和用法,

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/595194.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

避雷!7.7分,新增1区TOP被标记On Hold,5本已被踢除!

本周投稿推荐 SSCI • 2/4区经管类,2.5-3.0(录用率99%) SCIE(CCF推荐) • 计算机类,2.0-3.0(最快18天录用) SCIE(CCF-C类) • IEEE旗下,1/2…

[入门] Unity Shader前置知识(5) —— 向量的运算

在Unity中,向量无处不在,我想很多人都使用过向量类的内置方法 normalized() 吧,我们都知道该方法是将其向量归一化从而作为一个方向与速度相乘,以达到角色朝任一方向移动时速度都相等的效果,但内部具体是如何将该向量进…

力扣每日一题109:有序链表转换二叉搜索树

题目 中等 给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为 平衡 二叉搜索树。 示例 1: 输入: head [-10,-3,0,5,9] 输出: [0,-3,9,-10,null,5] 解释: 一个可能的答案是[0,-3,9,-10,null,5],它…

Java毕设之学院党员管理系统的设计与实现

运行环境 环境说明: 开发语言:java 框架:springboot,vue JDK版本:JDK1.8 数据库:mysql5.7(推荐5.7,8.0也可以) 数据库工具:Navicat11 开发软件:idea/eclipse(推荐idea) Maven包:Maven3.3.9 系统实现 管理员功能实现 党员管理 管理员进入指定功能操作…

一款开源高性能AI应用框架

前言 LobeChat 是一个基于 Next.js 框架构建的 AI 会话应用,旨在提供一个 AI 生产力平台,使用户能够与 AI 进行自然语言交互。 LobeChat应用架构 LobeChat 的整体架构由前端、EdgeRuntime API、Agents 市场、插件市场和独立插件组成。这些组件相互协作&a…

css实现上下左右对勾选中状态角标

🍥左上角 🍥右上角 🍥左下角 🍥右下角: 🍥左上角: .blueBackground {position: relative;border: 1px solid #91c7f3;background: #F0F8FF !important;&:after {content: "";position: absolute;top:…

7 人赚 960 亿美元,数字天才的首次独舞

巴菲特股东大会 一年一度的巴菲特股东大会如常召开,只不过这次坐在老爷子左手边的不再是老搭档查理芒格,而是钦点的未来继任者,格雷格阿贝尔。 随着芒格(99岁)的离开,巴菲特(93岁)也…

突破销量瓶颈:亚马逊,速卖通,国际站销量提升实战技巧

1、精心选品:选品是亚马逊销售的第一步,也是至关重要的一步。卖家应该进行市场调研,了解消费者的需求和喜好,选择有市场潜力的产品。要注意产品的差异化,避免与竞争对手的产品过于相似。 2、优化产品详情页&#xff1…

【SpringMVC 】什么是SpringMVC(二)?如何整合ssm框架以及使用mybatisPlus?

文章目录 SpringMVC第三章1、ssm整合1、基本步骤1-3步4-5步6步7步8-12步13步14-15步2、添加数据3、删除数据4、配置事务5、修改数据2、pageHelpe分页1、基本步骤第四章1、mybatisPlus1、基本步骤1-45-7892、基本方法的使用查询2、新ssm项目1、基本步骤1-5678-910-111213-15Spri…

✌粤嵌—2024/4/29—轮转数组

代码实现&#xff1a; // 逆置数组 void nizhi_array(int *nums, int l, int r) { // 左闭右闭if (l > r) {return;}int i l, j r;while (i < j) {int temp nums[i];nums[i] nums[j];nums[j] temp;i;j--;} }void rotate(int *nums, int numsSize, int k) {if (k >…

CSAPP | Chapter 1 | 计算机系统漫游

CSAPP | Chapter 1 | 计算机系统漫游 计算机系统由系统软件与硬件组成。 对于一个简单的 C 程序 hello.c 来说&#xff0c;即便它非常简单&#xff0c;但是为了让它运行&#xff0c;系统的每个主要组成部分都需要协调工作。 #include <stdio.h>int main() {printf(&quo…

AI适老化!10秒一张的AI姓氏头像,居然要卖9块9?中老年用户都说好!

看短视频的你&#xff0c;一定会刷到过这样的直播间&#xff1a; 现在大家明白了&#xff0c;这是一个做姓氏图像的直播间。我刚开始刷到的时候也觉得这种头像好看&#xff0c;高大上&#xff0c;也想做一个这样的图像&#xff0c;来当自己的微信头像。 做这样的图像需要排队刷…

迅饶科技 X2Modbus 网关 AddUser 任意用户添加漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…

代码随想录算法训练营DAY43|C++动态规划Part5|1049.最后一块石头的重量II、494.目标和、474.一和零

文章目录 1049.最后一块石头的重量II思路CPP代码 ⭐️494.目标和回溯算法抽象成01背包问题CPP代码本题总结 474.一和零思路CPP代码 1049.最后一块石头的重量II 力扣题目链接 文章链接&#xff1a;1049.最后一块石头的重量II 视频链接&#xff1a;这个背包最多能装多少&#xff…

高中数学-三角函数之常见题型总结

相关公式 新教材&#xff0c;取消了和差化积与积化和差的三角函数题目 例题1 解析 根据条件tanθ -2&#xff0c;我们应该就要想到&#xff0c;把待求式的角向θ靠拢 所以要想到如何降角&#xff0c;将2θ化成θ&#xff0c;那么&#xff0c;想到的公式就是&#xff1a;正弦…

【C++第三阶段】Set Map容器 员工分组案例

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 Set容器构造和赋值大小和交换插入和删除一次性迭代器&#xff08;可能迅速失效的迭代器&#xff09;长久保留的迭代器如何判断迭代器是否一次性 查找和统计set和multiset的区别pari对…

【notes2】并发,IO,内存

文章目录 1.线程/协程/异步&#xff1a;并发对应硬件资源是cpu&#xff0c;线程是操作系统如何利用cpu资源的一种抽象2.并发&#xff1a;cpu&#xff0c;线程2.1 可见性&#xff1a;volatile2.2 原子性&#xff08;读写原子&#xff09;&#xff1a;AtomicInteger/synchronized…

239 基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF(粒子滤波)三种算法的估计结果比较

基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF&#xff08;粒子滤波&#xff09;三种算法的估计结果比较&#xff0c;输出估计误差&#xff0c;并单独对粒子滤波进行估计及其置信区间可视化。程序已调通&#xff0c;可直接运行。 239 EKF(扩展卡尔曼滤波) - 小红书 …

Unity | Shader基础知识(第十三集:编写内置着色器阶段总结和表面着色器的补充介绍)

目录 前言 一、表面着色器的补充介绍 二、案例viewDir详解 1.viewDir是什么 2.viewDir的作用 3.使用viewDir写shader 前言 注意观察的小伙伴会发现&#xff0c;这组教程前半部分我们在编写着色器的时候&#xff0c;用的是顶点着色器和片元着色器的组合。 SubShader{CGPRO…

Java转Kotlin

Kotlin 是一种静态编程语言 2011JetBrains开始开发Kotlin&#xff0c;用于多平台应用&#xff08;能脱离虚拟机&#xff0c;直接编译成可以在win,mac,linux运行的二进制代码&#xff09; 2017获得谷歌官方支持 语法简洁&#xff08;减少了大量的样板代码&#xff0c;语法糖&…