js常见代码输出问题之promise,await,变量提升以及闭包(包括例子以及详细解析)
这里写目录标题
- 异步事件循环
- 宏任务微任务
- 1. 执行顺序
- 2. 分类
- Promise代码输出
- 1. promise.then执行时机
- 2. 宏任务微任务的多轮次
- 3. .then .catch会返回新的promise
- 4. 返回任意一个非 promise 的值都会被包裹成 promise 对象
- 5. .then .catch 的值不能是promise本身
- 6. 值透传
- 7. .finally
- 8. 捕获错误
- 9. promise.all和promise.race
- Async await
- 1. async搭配promise
- 2. async中抛出错误
- 作用域、变量提升、闭包
- 变量提升
- 1. 全局变量赋值给了一个局部变量
- 2. Function 和 var 都会变量提升
- 3. function的变量提升
- 作用域
- 闭包
- 例一
- 例二
异步事件循环
宏任务微任务
1. 执行顺序
先执行微任务再执行宏任务,注意宏任务微任务的多轮次,每执行完一次宏任务后都要检查有没有可执行的微任务
2. 分类
宏任务:setTimeout、setInterval、I/O 操作(如文件读取、网络请求等)、UI 渲染
微任务:Promise 的 then、catch、finally、process.nextTickMutationObserver
Promise代码输出
promise.then是微任务,执行要等所有宏任务执行完并且promise内部状态发生变化,状态改变后不会再更改
1. promise.then执行时机
<script>
const promise = new Promise((resolve, reject) => {console.log(1);setTimeout(() => {console.log("timerStart");resolve("success");console.log("timerEnd");}, 0);console.log(2);
});
//由于Promise的状态此时还是pending,所以promise.then先不执行
promise.then((res) => {console.log(res);
});
console.log(4);
//最终输出1 2 4 timerStart timerEnd success
</script>
2. 宏任务微任务的多轮次
<script>
Promise.resolve().then(() => {console.log('promise1');//进入第二轮宏任务const timer2 = setTimeout(() => {console.log('timer2')}, 0)
});
const timer1 = setTimeout(() => {console.log('timer1')//进入第二轮微任务,先执行Promise.resolve().then(() => {console.log('promise2')})
}, 0)
console.log('start');
//输出 start promise1 timer1 promise2 timer2</script>
console.log('1');setTimeout(function() {console.log('2');process.nextTick(function() {console.log('3');})new Promise(function(resolve) {console.log('4');resolve();}).then(function() {console.log('5')})
})
process.nextTick(function() {console.log('6');
})
new Promise(function(resolve) {console.log('7');resolve();
}).then(function() {console.log('8')
})setTimeout(function() {console.log('9');process.nextTick(function() {console.log('10');})new Promise(function(resolve) {console.log('11');resolve();}).then(function() {console.log('12')})
})
//输出1 7 6 8 2 4 3 5 9 11 10 12
3. .then .catch会返回新的promise
<script>
Promise.resolve(1).then(res => {console.log(res);//return 2包装为resolve(2) 进入下一个.thenreturn 2;}).catch(err => {return 3;}).then(res => {console.log(res);});//输出 1 2
</script>
4. 返回任意一个非 promise 的值都会被包裹成 promise 对象
<script>
Promise.resolve().then(() => {//这里会被.then捕获return new Error('error!!!')
}).then(res => {console.log("then: ", res)
}).catch(err => {console.log("catch: ", err)
})
//输出"then: " "Error: error!!!"
</script>
5. .then .catch 的值不能是promise本身
<script>
const promise = Promise.resolve().then(() => {return promise;
})
//进入死循环
promise.catch(console.err)
</script>
6. 值透传
<script>//.then.catch传入非函数会发生值透传
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)//输出1
</script>
7. .finally
- .finally()方法不管Promise对象最后的状态如何都会执行
- .finally()方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是无法知道Promise最终的状态是resolved还是rejected的
- .finally的返回值如果在没有抛出错误的情况下默认会是上一个Promise的返回值
- .finally 本质上是then方法的特例
8. 捕获错误
Promise.reject('err!!!')//在这里reject的错误直接被.then的err捕获而不是进入.catch.then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})//输出error err!!!
//无论是thne还是catch中,只要throw 抛出了错误,就会被catch捕获
//如果没有throw出错误,就被继续执行后面的then
Promise.resolve().then(() => {console.log('1');throw 'Error';
}).then(() => {console.log('2');
}).catch(() => {console.log('3');throw 'Error';
}).then(() => {console.log('4');
}).catch(() => {console.log('5');
}).then(() => {console.log('6');
});
//输出1 3 5 6
9. promise.all和promise.race
function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
//输出 1 2 3 [1,2 3]
//所有输入的promise都成功解析后返回数组
Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))
function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
//输出 1 result:1 2 3
//promise.race只捕获第一个结果无论成功或失败,且不再捕获
Promise.race([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log('result: ', res)).catch(err => console.log(err))
Async await
async单独使用为同步,搭配await实现异步,可以理解为await后的语句放入new Promise中,下一行及之后放入promise.then中
1. async搭配promise
async function async1 () {console.log('async1 start');await new Promise(resolve => {//new Promise立即执行,但状态保持pending导致会暂停在这里console.log('promise1')//在这里执行resolve会使async1继续执行})console.log('async1 success');return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
2. async中抛出错误
async function async1 () {await async2();console.log('async1');return 'async1 success'
}
async function async2 () {return new Promise((resolve, reject) => {console.log('async2')//如果async函数中抛出了错误,就会终止错误结果,不会继续向下执行//如果想让其执行可以用catch捕获错误reject('error')})
}
async1().then(res => console.log(res))
作用域、变量提升、闭包
变量提升
1. 全局变量赋值给了一个局部变量
var x = y = 1; 实际上这里是从右往左执行的,首先执行y = 1, 因为y没有使用var声明,所以它是一个全局变量,然后第二步是将y赋值给x,讲一个全局变量赋值给了一个局部变量,最终,x是一个局部变量,y是一个全局变量,所以打印x是报错
(function(){var x = y = 1;
})();
var z;console.log(y); // 1
console.log(z); // undefined
console.log(x); // Uncaught ReferenceError: x is not defined
2. Function 和 var 都会变量提升
var friendName = 'World';
(function() {
//相当于这里多了一行var friendNameif (typeof friendName === 'undefined') {var friendName = 'Jack';console.log('Goodbye ' + friendName);} else {console.log('Hello ' + friendName);}
})();
3. function的变量提升
function fn1(){console.log('fn1')
}
var fn2fn1()
fn2()fn2 = function() {console.log('fn2')
}fn2()
//输出
//fn1
//Uncaught TypeError: fn2 is not a function
//fn2
作用域
function a() {var temp = 10;function b() {console.log(temp); // 10}b();
}
a();function a() {var temp = 10;b();
}
function b() {console.log(temp); // 报错 Uncaught ReferenceError: temp is not defined
}
a();
闭包
例一
function fun(n, o) {
//当传入实参多于形参时,剩下的形参为undefinedconsole.log(o)return {fun: function(m){//返回对象,再次进入fun,打印o//当作用域中没有n时,向上作用域寻找return fun(m, n);}};
}
//输出
//undefined 0 0 0
//undefined 0 1 2
//undefined 0 1 1
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1); c.fun(2); c.fun(3);
例二
解释
由于在匿名函数中,又重新定义了函数g,就覆盖了外部定义的变量g,所以,这里调用的是内部函数 g 方法,返回为 true,当一个布尔值参与到条件运算的时候,true 会被看作 1, 而 false 会被看作 0。现在条件变成了 [] == 0 的问题了,当一个对象参与条件比较的时候,它会被求值,求值的结果是数组成为一个字符串,[] 的结果就是 ‘’ ,而 ‘’ 会被当作 0 ,所以,条件成立
f = function() {return true;};
g = function() {return false;};
(function() { if (g() && [] == ![]) { f = function f() {return false;}; function g() {return true;} }
})();
console.log(f());
相关文章:
js常见代码输出问题之promise,await,变量提升以及闭包(包括例子以及详细解析)
这里写目录标题 异步事件循环宏任务微任务1. 执行顺序2. 分类 Promise代码输出1. promise.then执行时机2. 宏任务微任务的多轮次3. .then .catch会返回新的promise4. 返回任意一个非 promise 的值都会被包裹成 promise 对象5. .then .catch 的值不能是promise本身6. 值透传7. .…...
遗传算法与深度学习实战(27)——进化卷积神经网络
遗传算法与深度学习实战(27)——进化卷积神经网络 0. 前言1. 自定义交叉算子2. 自定义突变操作符3. 进化卷积神经网络小结系列链接 0. 前言 DEAP toolbox 中提供的标准遗传操作符对于自定义的网络架构基因序列来说是不够的。这是因为任何标准的交叉算子…...
【Vue3】前端使用 FFmpeg.wasm 完成用户视频录制,并对视频进行压缩处理
强烈推荐这篇博客!非常全面的一篇文章,本文是对该博客的简要概括和补充,在不同技术栈中提供一种可行思路,可先阅读该篇文章再阅读本篇: FFmpeg——在Vue项目中使用FFmpeg(安装、配置、使用、SharedArrayBu…...
基础算法——前缀和
由于比赛基本都是采用Dev-C所以,算法篇基本都是采用Dev-C来解释(版本5.11,c11) 首先介绍一下前缀和算法 给定一个数组,有q次询问,每次询问: 两个整数l,r,求出数组 l 到 r的结果 遇…...
spring实例化对象的几种方式(使用XML配置文件)
前言 Spring框架作为一个轻量级的控制反转(IoC)容器,为开发者提供了多种对象实例化的策略。通过这些策略,开发者可以更加灵活地控制对象的生命周期和依赖关系。无论是通过XML配置、注解配置还是Java配置,Spring都能…...
【二叉树】力扣 129.求根节点到叶子节点数字之和
一、题目 二、思路 每找到一个非空节点,之前路径上的所有节点的数量级都要增加1个单位。例如,当前节点为3,之前的节点路径为1 -> 2,presum 1 * 10 2 12,现在路径变为了 1 -> 2 -> 3,sum pres…...
深度学习物体检测之YOLOV5源码解读
V5比前面版本偏工程化,项目化,更贴合实战 一.V5版本项目配置 (1)整体项目概述 首先github直接查找yolov5,下载下来即可。在训练时,数据是怎么处理的?网络模型架构是怎么设计的(如各层的设计)?yolov5要求是大于python3.8与大于等…...
音频数据采样入门详解 - 给Python初学者的简单解释
音频数据采样入门详解 - 给Python初学者的简单解释 声音是如何变成数字的?什么是采样率?为什么要懂这个?Python小例子总结 大家好!今天我们来聊一个有趣的话题:音频数据是如何在计算机中处理的。让我用最简单的方式来解…...
Unity类银河战士恶魔城学习总结(P179 Enemy Archer 弓箭手)
教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了敌人弓箭手的制作 Enemy_Archer.cs 核心功能 状态机管理敌人的行为 定义了多个状态对象(如 idleState、moveState、attackState 等),通过状态机管理敌人的…...
SpringCloud集成sleuth和zipkin实现微服务链路追踪
文章目录 前言技术积累spring cloud sleuth介绍zipkin介绍Zipkin与Sleuth的协作 SpringCloud多模块搭建Zipkin Server部署docker pull 镜像启动zipkin server SpringCloud 接入 Sleuth 与 Zipkinpom引入依赖 (springboot2.6)appilication.yml配置修改增加测试链路代码 调用微服…...
Python随机抽取Excel数据并在处理后整合为一个文件
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,基于其中每一个文件,随机从其中选取一部分数据,并将全部文件中随机获取的数据合并为一个新的Excel表格文件的方法。 首先,我们来明确一下本文的具体需求。…...
Linux+Docker onlyoffice 启用 HTTPS 端口支持
文章目录 一、需求二、配置2.1 创建容器2.2 进入容器2.3 生成私钥和证书 2.4 测试访问 一、需求 上篇文章介绍了如何搭建一个 onlyoffice 在线预览服务,但是我们实际场景调用该服务的网站是协议是 https 的 ,但是 onlyoffice 服务还没做配置,…...
在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c
在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c 1. Installing the extension (在 Visual Studio Code 中安装插件)1.1. Extensions for Visual Studio Code1.2. C/C1.2.1. Pre-requisites 1.3. Makefile Tools 2. Configuring your project (配置项目)2.1.…...
python中math模块常用函数
文章目录 math模块简介各种三角函数反三角函数取整函数欧几里得距离绝对值最大公约数开根号幂阶乘函数 math模块简介 math模块是python标准库的一部分,提供了对于浮点数相关的数学运算,下面是常用的一些function 各种三角函数反三角函数 math.cos、ma…...
优化 Vue 3 开发体验:配置 Vite 使用 WebStorm 作为 Vue DevTools 的默认编辑器
优化 Vue 3 开发体验:配置 Vite 使用 WebStorm 替代 VS Code 作为 Vue DevTools 的默认编辑器 在 Vue 3 项目开发中,合理配置开发工具可以大大提升我们的工作效率。本文将介绍如何配置 Vite,使其在使用 Vue DevTools 时将默认编辑器从 VS Co…...
【C语言练习(9)—有一个正整数,求是几位数然后逆序打印】
C语言练习(9) 文章目录 C语言练习(9)前言题目题目解析结果总结 前言 主要到整数的取余(%)和整数的取商(/),判断语句if…else if …else的使用 题目 给一个不多于3位的正整数,要求:一、求它是几位数&…...
热敏打印机的控制
首次接触热敏打印机,本来没有特别之处,花了大概十天时间完成一款猫学王热敏打印机,给到客户体验后,客户反馈说打字看起来不明显,打印照片有条纹,所以引起了我对于他的关注,几点不足之处需要优化…...
【closerAI ComfyUI】电商赋能,AI模特套图生产,各种姿势自定义,高度保持人物服饰场景一致性,摆拍街拍专用
closerAIGCcloserAI,一个深入探索前沿人工智能与AIGC领域的资讯平台,我们旨在让AIGC渗入我们的工作与生活中,让我们一起探索AIGC的无限可能性!aigc.douyoubuy.cn 【closerAI ComfyUI】电商赋能,AI模特套图生产,各种姿势自定义,高度保持人物服饰场景一致性,摆拍街拍专用…...
ARM学习(36)静态扫描规则学习以及工具使用
笔者来学习了解一下静态扫描以及其规则,并且亲身是实践一下对arm 架构的代码进行扫描。 1、静态扫描认识 静态扫描:对代码源文件按照一定的规则进行扫描,来发现一些潜在的问题或者风险,因为不涉及代码运行,所以其一般只是发现一些规范或则一些质量问题,当然这些可能存在潜…...
使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群
文章目录 使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群Redis 主从架构简介Redis Sentinel 简介配置文件1. 主节点配置 (redis-master.conf)2. 从节点配置 (redis-slave1.conf 和 redis-slave2.conf)redis-slave1.confredis-slave2.conf3. Sentinel 配置 (sentin…...
TypeScript类型安全进阶:Readonly和Required在状态管理中的妙用
TypeScript类型安全进阶:Readonly和Required在状态管理中的妙用 状态管理是现代前端开发中不可或缺的一环,而TypeScript的类型系统为我们提供了强大的工具来确保状态的安全性。在Redux、MobX等流行状态管理库中,Readonly和Required这两个工具…...
RHCE练习
练习: 1. 在4月份的周一到周三的上午11点执行 0 11 * 4 1-3 2. 每天早上7点到上午11点且每2小时执行一次 0 7-11/2 * * *3. 每天6点执行 0 6 * * * 4. 每周六凌晨4点执行 0 4 * * 65. 每周六凌晨4点05执行 5 4 * * 66. 每天8:40执行 40 8 * * *7. 在每天…...
“德智米”齐聚港股!德适高研发高增长,领跑 AI 医疗新赛道
随着德适正式登陆港交所,北京智谱、上海 MiniMax、杭州德适组成的 “德智米”AI 三强正式齐聚港股,勾勒出中国 AI 产业从底层基建、C 端应用到 B 端垂直落地的完整版图。其中,德适以“医学影像大模型 医疗垂直场景 高增长商业化”的独特定位…...
AI大模型学习路线图:小白程序员必看,收藏这份高薪入局指南!
AI大模型学习路线图:小白程序员必看,收藏这份高薪入局指南! 本文提供了一套完整的AI大模型学习路线,涵盖大模型基础认知、核心技术(RAG、Prompt、Agent)、开发基础能力、应用场景落地、项目实操流程及面试求…...
覆盖数十个行业,GEO 如何帮不同赛道企业实现精准获客?
在 AI 搜索全面普及的当下,无论哪个行业的企业,都面临着同一个问题:如何让自己的产品与服务,在用户的 AI 搜索结果中被优先推荐、精准触达目标客户。GEO(AI 搜索生成引擎优化)的出现,为不同行业…...
紧固件模具是什么?生产工艺、类型及应用详解_FES上海紧固件展
2026第十六届上海紧固件专业展Fastener Expo Shanghai 2026将于6月24日至26日在国家会展中心(上海)举行。展会由上海上搜展览与华人螺丝网联合主办,并获得中国五矿化工进出口商会五金紧固件分会支持,整体展览规模约70,000平方米&a…...
10款主流施工项目管理系统对比:建筑工程企业选型参考
本文将深入对比10款建筑工程项目管理系统:Worktile、Oracle Primavera P6、Oracle Aconex、Autodesk Build、Procore、Microsoft Project、Smartsheet、monday.com、Jira Confluence、广联达数字项目管理平台。文章将从定位、适用规模、部署方式、核心模块、安全合…...
关系型数据库星型模型聚合表生成
在关系型数据库(MySQL、Oracle、SQL Server等)中,通过星型模型模拟多维分析结构,高效生成聚合表,解决报表查询慢、多维分析繁琐、实时计算压力大等核心痛点。 一、前置基础 星型模型是关系型数据库模拟多维结构的最优方…...
Codesys软运动控制进阶:用SMC_FreeEncoder为ECAT轴搭建一个“虚拟手轮”调试工具
Codesys软运动控制进阶:用SMC_FreeEncoder为ECAT轴搭建虚拟手轮调试工具 在自动化设备开发周期中,机械安装与电气调试往往存在时间差。当机械部件尚未就位或伺服驱动器临时故障时,如何提前验证运动控制逻辑?传统做法是等待硬件就绪…...
实战指南:利用Hydra与SNETCracker加固3389远程桌面安全
1. 3389端口与远程桌面安全基础 3389端口是Windows远程桌面协议(RDP)的默认通信端口,就像你家大门的钥匙孔。想象一下,如果钥匙孔被所有人知道位置,又没装猫眼和防盗链,会是什么后果?这就是为什…...
