前端JavaScript篇之setTimeout、Promise、Async/Await 的区别

目录

  • setTimeout、Promise、Async/Await 的区别
    • **setTimeout**:
      • 思路
      • 需要注意的
    • **Promise**:
      • 思路
      • 需要注意的
    • **Async/Await**:
      • 思路
      • 需要注意的
    • 总结


setTimeout、Promise、Async/Await 的区别

setTimeout:

  • 概念setTimeout是JavaScript中的一个函数,用于在一定的时间间隔后执行指定的代码。
console.log('script start') //1. 打印 script start
setTimeout(function(){
console.log('settimeout') // 4. 打印 settimeout
}) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end') //3. 打印 script start
// 输出顺序:script start->script end->settimeout

请添加图片描述

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. setTimeout(function(){ console.log('settimeout') }):调用setTimeout函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数将会被添加到任务队列中,等待主线程执行完毕后立即执行。
  3. console.log('script end'):立即在主线程中执行,打印出"script end"。

由于setTimeout的回调函数并未设置延迟,它会在主线程执行完毕后立即执行,因此输出顺序应该是:script start -> script end -> settimeout。

需要注意的

  • setTimeout 的回调函数在这里并没有设置延迟时间,因此会立即执行。
  • JavaScript 运行环境中存在着主线程和任务队列,当主线程执行完毕后,会去检查任务队列中是否有任务需要执行,这时才会执行setTimeout的回调函数。
// 使用setTimeout模拟一个简单的延迟操作,输出一条消息console.log('Start') // 同步操作// 模拟延迟操作,2秒后输出消息
setTimeout(() => {console.log('Delayed message after 2 seconds')
}, 2000)console.log('End') // 同步操作

请添加图片描述

在这个案例中,setTimeout函数用于模拟一个简单的延迟操作。在代码执行时,会先输出"Start"和"End"(同步操作),然后等待2秒后输出"Delayed message after 2 seconds"。需要注意的是,setTimeout不会阻塞后续的代码执行,而是在指定的时间后将回调函数加入到任务队列中,等待执行。

setTimeout允许我们在指定的时间后执行一段代码,它是一种简单的异步操作方式。

  • 需要注意:需要注意的是,setTimeout并不会阻塞后续的代码执行,而是在指定的时间后将回调函数加入到任务队列中,等待执行。

Promise:

  • 概念:Promise是ES6中引入的一种用于处理异步操作的对象,代表了一个异步操作最终会产生的值或原因。
console.log('script start')
let promise1 = new Promise(function (resolve) {console.log('promise1')resolve()console.log('promise1 end')
}).then(function () {console.log('promise2')
})
setTimeout(function () {console.log('settimeout')
})
console.log('script end')

请添加图片描述

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. let promise1 = new Promise(function (resolve) { ... }):创建一个新的Promise对象,立即执行传入的函数。在这个函数中:
    • console.log('promise1'):立即在主线程中执行,打印出"promise1"。
    • resolve():立即将Promise状态从pending变为fulfilled。
    • console.log('promise1 end'):立即在主线程中执行,打印出"promise1 end"。
  3. .then(function () { console.log('promise2') }):注册在Promise对象状态变为fulfilled后执行的回调函数,但是由于Promise状态已经是fulfilled,所以这个回调函数会被添加到微任务队列中,等待主线程执行完毕后立即执行。
  4. setTimeout(function(){ console.log('settimeout') }):调用setTimeout函数,并定义其完成后执行的回调函数,但没有指定延迟的时间。因此,回调函数会被添加到任务队列中,等待主线程执行完毕后立即执行。
  5. console.log('script end'):立即在主线程中执行,打印出"script end"。

由于微任务(Promise)优先级高于宏任务(setTimeout),且Promise对象的状态已经是fulfilled,因此输出顺序应该是:script start -> promise1 -> promise1 end -> script end -> promise2 -> settimeout。

需要注意的

  • Promise对象中的函数是立即执行的,而.then()中的回调函数是异步执行的,会被添加到微任务队列中。
  • 微任务(Promise)会优先于宏任务(setTimeout)执行。
// 使用Promise模拟一个简单的异步操作,比如模拟加载数据// 模拟异步操作,返回一个Promise对象
function loadData() {return new Promise((resolve, reject) => {// 模拟异步操作,比如从服务器获取数据setTimeout(() => {const data = 'Simulated data loaded'resolve(data) // 异步操作成功,将数据传递给resolve}, 2000)})
}// 调用模拟的异步操作
loadData().then(data => {console.log(data) // 在异步操作成功后输出数据}).catch(error => {console.error('Error:', error) // 捕获可能出现的错误})

请添加图片描述

在这个案例中,loadData函数返回一个Promise对象,模拟了一个简单的异步操作(比如从服务器获取数据)。通过setTimeout模拟了2秒的延迟,然后将数据传递给resolve,表示异步操作成功。在调用loadData后,使用.then()方法处理异步操作成功的情况,并使用.catch()方法捕获可能出现的错误。这样可以更好地管理异步操作的状态和结果。
Promise提供了一种更结构化和灵活的处理异步操作的方式,可以通过.then()方法链式处理异步操作的结果。

  • 需要注意:需要注意的是,Promise可以处于pending、fulfilled或rejected三种状态之一,并且可以通过.then().catch()方法来处理异步操作的结果或错误。

Async/Await:

  • 概念:Async/Await是建立在Promise之上的语法糖,使得异步代码看起来更像同步代码。
async function async1() {console.log('async1 start')await async2()console.log('async1 end')
}
async function async2() {console.log('async2')
}
console.log('script start')
async1()
console.log('script end')

请添加图片描述

思路

  1. console.log('script start'):立即在主线程中执行,打印出"script start"。
  2. async1():调用async1函数,进入async1函数内部执行。
    • console.log('async1 start'):立即在主线程中执行,打印出"async1 start"。
    • await async2():使用await关键字等待async2函数执行完成。此时,主线程会暂时离开async1函数,执行async2函数。
      • console.log('async2'):立即在主线程中执行,打印出"async2"。
    • 回到async1函数内部。
    • console.log('async1 end'):立即在主线程中执行,打印出"async1 end"。
  3. console.log('script end'):立即在主线程中执行,打印出"script end"。

根据代码执行的顺序和await关键字的特性,输出顺序应该是:script start -> async1 start -> async2 -> script end -> async1 end。

需要注意的

  • await关键字会使主线程暂时离开async1函数,执行async2函数,直到async2函数执行完成后再回到async1函数继续执行后续代码。
  • await关键字后面的表达式应该是一个返回Promise对象的表达式,它会暂停async1函数的执行,直到这个Promise对象状态变为resolved或rejected。
  • await关键字只能在async函数内部使用。
// 使用Async/Await重写Promise的案例,使得异步操作更加直观// 模拟异步操作,返回一个Promise对象
function loadData() {return new Promise((resolve, reject) => {// 模拟异步操作,比如从服务器获取数据setTimeout(() => {const data = 'Simulated data loaded'resolve(data) // 异步操作成功,将数据传递给resolve}, 2000)})
}// 使用Async/Await重写Promise的案例
async function fetchData() {try {console.log('Start fetching data') // 同步操作const data = await loadData() // 等待异步操作完成console.log(data) // 在异步操作成功后输出数据console.log('Data fetched successfully') // 异步操作成功后的操作} catch (error) {console.error('Error:', error) // 捕获可能出现的错误}
}// 调用使用Async/Await重写的异步函数
fetchData()

请添加图片描述

在这个案例中,fetchData函数使用了async关键字声明,内部使用await等待loadData函数返回的Promise对象。当调用fetchData时,它会立即执行,并在遇到await关键字时暂停执行,直到loadData函数返回的Promise状态变为resolved。这样使得异步代码看起来更像同步代码,易于理解和维护。
Async关键字声明的函数内部可以使用Await关键字等待Promise对象的解决,从而让异步代码更加清晰易懂。

  • 需要注意:需要注意的是,使用Async/Await可以让异步代码看起来更像同步代码,避免了嵌套过深的回调函数或者过多的Promise链式调用。

await关键字用于等待一个异步操作的完成,并暂停async函数的执行,直到这个异步操作返回一个Promise对象。通过在await后面的表达式中调用一个返回Promise的函数,可以实现同步的效果。在await等待的过程中,JavaScript引擎可以继续执行其他任务,从而充分利用了线程资源。

需要注意的是,await关键字只能在async函数内部使用,并且只能等待返回Promise对象的表达式。在await后面的代码将在等待的异步操作完成后继续执行。

总结

  • setTimeout用于简单的延迟操作,但不适合复杂的异步操作处理。
  • Promise提供了更结构化和灵活的异步操作处理方式,支持链式调用,能够更好地管理异步操作的状态和结果。
  • Async/Await建立在Promise之上,使得异步代码更像同步代码,更易于理解和维护。

以上三种方式各有优劣,根据具体场景选择合适的方式来处理异步操作非常重要。

持续学习总结记录中,回顾一下上面的内容:

  • setTimeout用于简单的延迟操作,但不适合复杂的异步操作处理。
  • Promise提供了更结构化和灵活的异步操作处理方式,支持链式调用,能够更好地管理异步操作的状态和结果。
  • Async/Await建立在Promise之上,使得异步代码更像同步代码,更易于理解和维护。
    以上三种方式各有优劣,根据具体场景选择合适的方式来处理异步操作非常重要。

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

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

相关文章

Leetcode 3036. Number of Subarrays That Match a Pattern II

Leetcode 3036. Number of Subarrays That Match a Pattern II 1. 解题思路2. 代码实现 3036. Number of Subarrays That Match a Pattern II 1. 解题思路 这一题其实有点水,因为本质上还是一道套路题目,和前两周的两道题目一样,都是考察的…

c++求三个数中最大数

#include<iostream> using namespace std; int main() { int a,b,c; cout<<"请输入三个数字"<<endl;//end后面为小写的L cin>>a>>b>>c; if(a>b&&a>c) cout<<"最大数为a:"<<a<<e…

【MySQL】——数值函数的学习

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-Z1fAnfrxGD7I5gqp {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

人工智能:从概念到现实的辉煌历程

引言 自20世纪中叶以来&#xff0c;人工智能&#xff08;Artificial Intelligence, AI&#xff09;作为一门前沿科技领域&#xff0c;其发展进程犹如一部波澜壮阔的史诗。本文将带领读者走进AI的世界&#xff0c;探索它从最初的梦想设想&#xff0c;历经坎坷与突破&#xff0c…

JAVA设计模式之访问模式详解

访问者模式 1 访问者模式介绍 访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式. 访问者模式(Visitor Pattern) 的原始定义是&#xff1a;允许在运行时将一个或多…

Java集合 LinkedList

目录 LinkedList实例 LinkedList LinkedList是Java中的一个重要的数据结构&#xff0c;它实现了List接口&#xff0c;提供了链表数据结构的实现。LinkedList类中包含了各种常用的链表操作&#xff0c;如添加、删除、查找等。 LinkedList的特点是元素可以动态地添加到链表的任…

关于创建vue项目报错command failed: npm install --loglevel error

一、首先 在这个目录下有个文件叫.vuerc 二、其次 进去之后把里面的"useTaobaoRegistry": false,修改下&#xff0c;我之前是true&#xff0c;后来改成了false才成功。

我的2024新年-新Flag

一&#xff0c;缘由 新年新气象&#xff0c;这么多年来&#xff0c;自己也没有弄过什么年度flag&#xff0c;这次立flag&#xff0c;是自己的首次。都说&#xff1a;“没有理想&#xff0c;那跟咸鱼就没有区别”&#xff0c;试下不当咸鱼看看是什么感觉。其实&#xff0c;自己…

【数据结构】11 堆栈(顺序存储和链式存储)

定义 可认为是具有一定约束的线性表&#xff0c;插入和删除操作都在一个称为栈顶的端点位置。也叫后入先出表&#xff08;LIFO&#xff09; 类型名称&#xff1a;堆栈&#xff08;STACK&#xff09; 数据对象集&#xff1a; 一个有0个或者多个元素的有穷线性表。 操作集&#…

Window中出现 结束服务又自动重启的解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法前言 长期使用Linux操作系统,对于Window进程如何关闭开启,推荐阅读:Window命令行 如何查看以及关闭进程 而现在遇到进程无法强制kill,过一会自动启动! 对这种方式如何强制关闭,可看下文 1. 问题所示 起初在驱动某个服务的…

单片机与外设的交互

单片机与外设的交互是嵌入式系统中非常重要的一个基础知识点。单片机是一个集成在同一芯片上的中央处理器、存储器和输入/输出接口,它可以根据用户编写的程序与各种外部设备即外设进行交互。单片机与外设之间的交互主要通过单片机上的输入/输出口(I/O口)来实现。 I/O口的工作原…

Springboot 2.5.x如何集成Nacos 2.x的配置管理功能?

文章目录 什么是nacos安装单机版nacos物理机安装docker安装springboot如何集成Nacos?增加maven依赖在application.yml中增加配置在启动类中增加nacos注解如何读取配置如何使用配置?调用示例总结什么是nacos Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service…

【MySQL】-21 MySQL综合-8(MySQL默认值+MySQL非空约束+MySQL查看表中的约束)

MySQL默认值MySQL非空约束MySQL查看表中的约束 MySQL默认值在创建表时设置默认值约束在修改表MySQL默认值在创建表时设置默认值约束在修改表时添加默认值约束删除默认值约束删除默认值约束 MySQL非空约束在创建表时设置非空约束在修改表时添加非空约束删除非空约束 MySQL查看表…

Pytorch 复习总结 1

Pytorch 复习总结&#xff0c;仅供笔者使用&#xff0c;参考教材&#xff1a; 《动手学深度学习》 本文主要内容为&#xff1a;Pytorch 张量的常见运算、线性代数、高等数学、概率论。 Pytorch 张量的常见运算、线性代数、高等数学、概率论 部分 见 Pytorch 复习总结 1&…

一个适用于后渗透期间的信息收集工具

介绍 Pillager是一个适用于后渗透期间的信息收集工具&#xff0c;可以收集目标机器上敏感信息&#xff0c;方便下一步渗透工作的进行。 支持 注&#xff1a;✅表示经过测试&#xff0c;&#x1f6a7;表示理论上支持但未经测试&#xff0c;❌表示无此功能或不支持 后续将会陆续…

CSP-202006-1-线性分类器

CSP-202006-1-线性分类器 解题思路 通过比较第一个训练数据点的类别和直线函数值的正负来确定标准类别和标准函数值的正负。循环遍历训练数据中的每个点&#xff0c;计算直线函数值并与标准函数值比较&#xff0c;以确定该点所在的类别。 如果当前点的类别与标准类别一致&…

Lua: 一门轻量级、高效的脚本语言

Lua: 一门轻量级、高效的脚本语言 在当今软件开发的领域中&#xff0c;寻找一门既灵活又高效的脚本语言&#xff0c;一直是开发者们追求的目标。Lua作为一门小巧、高效、可嵌入的脚本语言&#xff0c;已经成为了众多开发者的首选之一。无论是游戏开发、嵌入式系统、Web 开发还是…

程序设计语言的组成

程序设计语言的组成 程序设计语言基本上由数据、运算、控制、传输组成 数据成分 数据是程序操作的对象&#xff0c;具有存储类别、类型、名称、作用域和生存期等属性 从不同角度可将数据进行不同的划分。 数据类型的分类如下&#xff1a; 按程序运行过程中数据的值能否改…

ncc匹配提速总结

我们ncc最原始的匹配方法是&#xff1a;学习模板w*h个像素都要带入ncc公式计算 第一种提速&#xff0c;学习模板是w*h&#xff0c;而我们支取其中的w/2*h/2,匹配窗口同理&#xff0c;计算量只有1/4。 另外一种因为ncc是线性匹配&#xff0c;我们在这上面也做了文章&#xff0…

Lua weak表

之前写过一篇博客专门介绍了weak表&#xff1a;Lua弱引用表-CSDN博客&#xff0c;这两天阅读了《programming in lua》后有了些新的体会&#xff0c;在这里只做一些之前没有了解的补充内容。 定义 Lua 自动进行内存的管理。程序只能创建对象&#xff08;表&#xff0c;函数等…