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服务端的各项功能代…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...