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…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
