前端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,一经查实,立即删除!

相关文章

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…

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才成功。

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

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

单片机与外设的交互

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

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

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

CSP-202006-1-线性分类器

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

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

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

ncc匹配提速总结

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

《UE5_C++多人TPS完整教程》学习笔记2 ——《P3 多人游戏概念(Multiplayer Concept)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P3 多人游戏概念&#xff08;Multiplayer Concept&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译…

如何把手机平板变为电脑的屏幕

文章目录 安装软件运行效果结尾 本文首发地址 https://h89.cn/archives/181.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 闲置的手机平板、触屏音箱等&#xff0c;均可作为电脑的扩展屏&#xff0c;为电脑增加一块显示屏&#xff0c;本文介绍如何使用免费的软件s…

DS Wannabe之5-AM Project: DS 30day int prep day12

Q1. Where is the confusion matrix used? Which module would you use to show it? 混淆矩阵 混淆矩阵常用于评估分类模型的性能&#xff0c;特别是在二分类或多分类问题中。它展示了实际类别与模型预测类别之间的关系。在Python中&#xff0c;可以使用sklearn.metrics模块…

代码随想录算法训练营DAY13 | 栈与队列 (3)

一、LeetCode 239 滑动窗口最大值 题目链接&#xff1a;239.滑动窗口最大值https://leetcode.cn/problems/sliding-window-maximum/ 思路&#xff1a;使用单调队列&#xff0c;只保存窗口中可能存在的最大值&#xff0c;从而降低时间复杂度。 public class MyQueue{Deque<I…

【闲谈】初识深度学习

在过去的十年中&#xff0c;深度学习彻底改变了我们处理数据和解决复杂问题的方式。从图像识别到自然语言处理&#xff0c;再到游戏玩法&#xff0c;深度学习的应用广泛且深入。本文将探讨深度学习的基础知识、关键技术以及最新的研究进展&#xff0c;为读者提供一个全面的视角…

第三节 zookeeper基础应用与实战2

目录 1. Watch事件监听 1.1 一次性监听方式&#xff1a;Watcher 1.2 Curator事件监听机制 2. 事务&异步操作演示 2.1 事务演示 2.2 异步操作 3. Zookeeper权限控制 3.1 zk权限控制介绍 3.2 Scheme 权限模式 3.3 ID 授权对象 3.4 Permission权限类型 3.5 在控制台…

Linux中孤儿/僵尸进程/wait/waitpid函数

孤儿进程&#xff1a; 概念&#xff1a;若子进程的父进程已经死掉&#xff0c;而子进程还存活着&#xff0c;这个进程就成了孤儿进程。 为了保证每个进程都有一个父进程&#xff0c;孤儿进程会被init进程领养&#xff0c;init进程成为了孤儿进程的养父进程&#xff0c;当孤儿…

DataBinding简易入门

简介 DataBinding是Google在18年推出的数据绑定框架&#xff0c;采用了MVVM模式来降低各模块之间代码的耦合度&#xff0c;使得整体代码逻辑设计更加清晰。众所周知&#xff0c;MVVM类似于MVC&#xff0c;主要目的是为分离View&#xff08;视图&#xff09;和Model&#xff08…

MATLAB知识点:isempty函数(★★★★☆)判断数组是否为空

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第…