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中异步函数的概念、定义和用法,

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PDF到TXT:一键解锁文本魅力,轻松实现格式转换!

PDF文件以其独特的跨平台、易阅读性受到了广大用户的青睐。但是,有时我们也需要将PDF文件转换为其他格式,以满足不同的需求。比如,有时候我们需要将PDF文件转换为TXT格式,以便在移动设备上轻松阅读或进行文本编辑。这时&#xff0…

3.ERC4626

ERC4626是一个vault,在DAI中,使用ETH换取DAI。其流程为先充值ETH到maker vault。 Vault 资产的管理、分红用户充值某项资产获取某个凭证该凭证作为分红、推出的依据Yield Farming/借贷/质押等 以太坊改进提案EIP:ethereum improvemwnt proposal 最初E…

BTCOIN的革命之路:通过SocialFi重塑全球金融生态系统

BTCOIN的革命之路:通过SocialFi重塑全球金融生态系统 今日,BTCOIN宣布发布WEB3.0论坛引发业内现象级关注:作为一个倡导WEB3.0理念的数字金融平台,在数字货币的波澜壮阔中,BTCOIN以其独特的生态定位和战略愿景&#xff…

AI大模型探索之路-训练篇15:大语言模型预训练之全量参数微调

系列篇章💥 AI大模型探索之路-训练篇1:大语言模型微调基础认知 AI大模型探索之路-训练篇2:大语言模型预训练基础认知 AI大模型探索之路-训练篇3:大语言模型全景解读 AI大模型探索之路-训练篇4:大语言模型训练数据集概…

图像分割入门-Unet++理论与实践

探索 U-net:改进的图像分割神经网络 引言 图像分割是计算机视觉领域中的重要任务,旨在将图像中的每个像素分配到特定的类别或区域。在许多应用中,如医学影像分析、自动驾驶和地块识别等领域,图像分割都扮演着关键角色。 U-net …

前端奇怪面试题总结

面试题总结 不修改下面的代码进行正常解构 这道题考的是迭代器和生成器的概念 let [a,b] {a:1,b:2}答案 对象缺少迭代器,需要手动加上 Object.prototype[Symbol.iterator] function* (){// return Object.values(this)[Symbol.iterator]()return yeild* Object.v…

Java常用命令总结 持续更新中!!!

蓝桥杯JAVA组 推荐输入输出示例 // 基础输入 import java.util.*;public class Main{public static void main(String[] args){} }// 非静态方法调用 new Main.Solution();//static函数里面调用非static函数 类.函数// 更快的输入方式 BufferedReader // 更快的输出方式 Print…

腾讯云服务器 宝塔面板部署小程序和后台教程

文章目录 目录 文章目录 安装流程 小结 概要部署流程技术细节小结 概要 本次的部署准备了3个域名,都是从二级域名映射出3个三级域名,域名注册可以在3大互联网官网购买一个域名就行。并且备案审核这些比较花费时间一般需要15工作日 部署流程 宝塔面板的…

【ITK统计】第一期 分类器

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享ITK中的分类器及其使用情况,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 在统计分…

GROUP_CONCAT超出1024截取

GROUP_CONCAT 是 MySQL 数据库中的一个函数,用于将来自同一个组的多个字符串连接成一个字符串结果。但是,GROUP_CONCAT 有一个默认的最大长度限制,即 1024 字符。这意味着,如果你尝试连接的字符串总长度超过 1024 字符&#xff0c…

强强联手!沃飞长空携手中信海直,开启空中交通新篇章

自古以来,人类就对天空充满了向往。而新一代航空革命性飞行器eVTOL的出现,让我们离智慧低空出行场景更进一步。目前,中国、美国、欧洲等国家和地区都在加紧布局低空经济产业,整个市场可谓是百家争鸣。随着国内外相关研发企业的不断…

沃伦·巴菲特将AI比做原子弹:“瓶中精灵”使诈骗成为最快增长产业|TodayAI

在伯克希尔哈撒韦公司的年度股东大会上,投资大师沃伦巴菲特对人工智能的未来提出了严重警告。巴菲特对这项可以模拟现实并产生误导性内容的技术表示担忧,他认为这将成为史上增长最快的行业之一。 巴菲特在会上说:“当你思考诈骗人们的潜力时…