【前端】手写代码输出题易错点汇总

两天更新完。

const promise = new Promise((resolve, reject) => {console.log(1);console.log(2);
});
promise.then(() => {console.log(3);
});
console.log(4);
//1
//2
//4

promise.then 是微任务,它会在所有的宏任务执行完之后才会执行,同时需要promise内部的状态发生变化,因为这里内部没有发生变化,一直处于pending状态,所以不输出3。

const promise1 = new Promise((resolve, reject) => {console.log('promise1')resolve('resolve1')
})
const promise2 = promise1.then(res => {console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
/*
promise1
1 Promise{<resolved>: resolve1}
2 Promise{<pending>}
resolve1
*/

直接打印Promise,会打印出它的状态值和参数。

const promise = new Promise((resolve, reject) => {console.log(1);setTimeout(() => {console.log("timerStart");resolve("success");console.log("timerEnd");}, 0);console.log(2);
});
promise.then((res) => {console.log(res);
});
console.log(4);
/*
1
2
4
timerStart
timerEnd
success
*/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
*/

代码执行过程如下:

  1. 首先,Promise.resolve().then是一个微任务,加入微任务队列
  2. 执行timer1,它是一个宏任务,加入宏任务队列
  3. 继续执行下面的同步代码,打印出start
  4. 这样第一轮宏任务就执行完了,开始执行微任务Promise.resolve().then,打印出promise1
  5. 遇到timer2,它是一个宏任务,将其加入宏任务队列,此时宏任务队列有两个任务,分别是timer1、timer2;
  6. 这样第一轮微任务就执行完了,开始执行第二轮宏任务,首先执行定时器timer1,打印timer1;
  7. 遇到Promise.resolve().then,它是一个微任务,加入微任务队列
  8. 开始执行微任务队列中的任务,打印promise2;
  9. 最后执行宏任务timer2定时器,打印出timer2;
const promise = new Promise((resolve, reject) => {resolve('success1');reject('error');resolve('success2');
});
promise.then((res) => {console.log('then:', res);
}).catch((err) => {console.log('catch:', err);
})
/*
then:success1
考察的就是Promise的状态在发生变化之后,就不会再发生变化
*/Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
/*
1
*/

then方法接受的参数是函数,而如果传递的并非是一个函数,这就会导致前一个Promise的结果会传递下面。Promise.resolve(3) 是一个 Promise 对象,不是一个函数。所以这个参数也被忽略。

const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')//状态改变}, 1000)
})
const promise2 = promise1.then(() => {//注意这是promise2throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {console.log('promise1', promise1)console.log('promise2', promise2)
}, 2000)
/*
promise1 Promise {<pending>}
promise2 Promise {<pending>}
promise1 Promise {<fulfilled>: "success"}
promise2 Promise {<rejected>: Error: error!!}
*/Promise.resolve(1).then(res => {console.log(res);//输出1return 2;//给到了最后的.then}).catch(err => {return 3;}).then(res => {console.log(res);//输出2});
/*
1   
2
*/

Promise是可以链式调用的,由于每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用, 它并不像一般任务的链式调用一样return this。
上面的输出结果之所以依次打印出1和2,是因为resolve(1)之后走的是第一个then方法,并没有进catch里,所以第二个then中的res得到的实际上是第一个then的返回值。并且return 2会被包装成resolve(2),被最后的then打印输出2。

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)//1

只需要记住一个原则:.then 或.catch 的参数期望是函数,传入非函数则会发生值透传。就是当它不存在。
第一个then和第二个then中传入的都不是函数,一个是数字,一个是对象,因此发生了透传,将resolve(1) 的值直接传到最后一个then里,直接打印出1。

Promise.resolve().then(() => {return new Error('error!!!')
}).then(res => {console.log("then: ", res)
}).catch(err => {console.log("catch: ", err)
})
/*
"then: " "Error: error!!!"
*/

返回任意一个非 promise 的值都会被包裹成 promise 对象,因此这里的return new Error(‘error!!!’)也被包裹成了return Promise.resolve(new Error(‘error!!!’)),因此它会被then捕获而不是catch。

const promise = Promise.resolve().then(() => {return promise;
})
promise.catch(console.err)
/*
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
*/

这里其实是一个坑,.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。

Promise.reject('err!!!').then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})//error err!!!

错误直接被then的第二个参数捕获了,所以就不会被catch捕获了

Promise.resolve('1').then(res => {console.log(res)}).finally(() => {console.log('finally')})
Promise.resolve('2').finally(() => {console.log('finally2')return '我是finally2返回的值'}).then(res => {console.log('finally2后面的then函数', res)})
/* 注意一下微任务队列顺序,Promise.resolve是同步代码 因为创建了一个promise
1
finally2
finally
finally2后面的then函数 2
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))
/*
1
2
3
[1, 2, 3]
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
function runReject (x) {const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
/*
`Error: ${x}`并不会打印,作为rejected 的原因传入
*/return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]).then(res => console.log(res)).catch(err => console.log(err))
/*
// 1s后输出
1
3
// 2s后输出
2
Error: 2 //进入catch
// 4s后输出
4
*/function runAsync(x) {const p = new Promise(r =>setTimeout(() => r(x, console.log(x)), 1000));return p;
}
function runReject(x) {const p = new Promise((res, rej) =>setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x));return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log("result: ", res)).catch(err => console.log(err));
/* 虽然race只捕获一次,但settimeout回调函数输出还是有的
0
Error: 0
1
2
3
*/async function async1() {console.log("async1 start");await async2();console.log("async1 end");
}
async function async2() {console.log("async2");
}
async1();
console.log('start')
/*
async1 start
async2
start
async1 end跳出async1函数后,执行同步代码start;在一轮宏任务全部执行完之后,再来执行await后面的内容async1 end。
await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中。
*/async function async1() {console.log("async1 start");await async2();console.log("async1 end");setTimeout(() => {console.log('timer1')}, 0)
}
async function async2() {setTimeout(() => {console.log('timer2')}, 0)console.log("async2");
}
async1();
setTimeout(() => {console.log('timer3')
}, 0)
console.log("start")
/*
async1 start
async2
start
async1 end
timer2
timer3
timer1
*/

代码的执行过程如下:

  1. 首先进入async1,打印出async1 start;
  2. 之后遇到async2,进入async2,遇到定时器timer2,加入宏任务队列,之后打印async2;
  3. 由于async2阻塞了后面代码的执行,所以执行后面的定时器timer3,将其加入宏任务队列,之后打印start;
  4. 然后执行async2后面的代码,打印出async1 end,遇到定时器timer1,将其加入宏任务队列;
  5. 最后,宏任务队列有三个任务,先后顺序为timer2,timer3,timer1,没有微任务,所以直接所有的宏任务按照先进先出的原则执行。
async function async1 () {console.log('async1 start');await new Promise(resolve => {console.log('promise1')})console.log('async1 success');return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
/*
script start
async1 start
promise1
script end
async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,所以在await之后的内容是不会执行的,包括async1后面的 .then。
*/

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

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

相关文章

基于深度学习和单目测距的前车防撞及车道偏离预警系统

随着人工智能与计算机视觉技术的飞速发展,高级驾驶辅助系统(ADAS)已成为现代汽车智能化的关键标志。它不仅能有效提升行车安全,还能为自动驾驶时代的全面到来奠定坚实基础。本文深入剖析一套功能完备、基于深度学习模型的 ADAS 系统的架构与核心实现,带您领略智能驾驶背后…

JWT(JSON Web Token)用户认证

1、颁发token <!--JWT依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.xml.bind</groupId>…

【质量管理】现代TRIZ(萃智)理论概述

一、什么是TRIZ理论 TRIZ理论,即发明问题解决理论(Teoriya Resheniya Izobreatatelskikh Zadatch),是由前苏联发明家根里奇阿奇舒勒(Genrich S. Altshuller)于1946年创立的。它是一门基于知识的、面向人的发明问题解决系统化方法学。TRIZ理论通过研究大量的专利,总结出技…

大模型学习笔记 day01 提示工程入门1.One-shot Few-shot提示学习法

如何应⽤和激发⼤语⾔模型的各⽅⾯能⼒ 提示⼯程 Prompt engineering 通过输⼊更加合理的提示&#xff0c;引导模型进⾏更有效的结果输出&#xff0c;本质上是⼀种引导和激发模型能⼒的⽅法更加轻量级的引导⽅法&#xff0c;尝试和实施的⻔槛更低&#xff1b;问题是受限于模型…

FPGA初级项目10——基于SPI的DAC芯片进行数模转换

FPGA初级项目10——基于SPI的DAC芯片进行数模转换 DAC芯片介绍 DAC 芯片&#xff08;数字模拟转换器&#xff09;是一种将数字信号转换为连续模拟信号&#xff08;如电压或电流&#xff09;的集成电路&#xff0c;广泛应用于电子系统中&#xff0c;连接数字世界与模拟世界。 …

如何在 Windows上安装 Python 3.6.5?

Windows 系统安装步骤 下载安装包 安装包下载链接&#xff1a;https://pan.quark.cn/s/9294ca0fd46a 运行安装程序 双击下载的 .exe 文件&#xff08;如 python-3.6.5.exe&#xff09;。 勾选 Add Python 3.6 to PATH&#xff08;重要&#xff01;这将自动配置环境变量&…

Cephalon端脑云:神经形态计算+边缘AI·重定义云端算力

前引&#xff1a;当算力不再是“奢侈品” &#xff0c;在人工智能、3D渲染、科学计算等领域&#xff0c;算力一直是横亘在个人与企业面前的“高墙”。高性能服务器价格动辄数十万元&#xff0c;专业设备维护成本高&#xff0c;普通人大多是望而却步。然而&#xff0c;Cephalon算…

【信息系统项目管理师】高分论文:论进度管理和成本管理(智慧城管平台项目)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划进度管理2、定义活动3、排列活动顺序4、估算活动资源5、估算活动持续时间6、制定进度计划7、控制进度论文 2018年8月,我作为项目经理参与了 XX市智慧城管平台项目的建设,该项目投资500万元人民币…

WebAssembly:开启高性能Web应用新时代

一、引言 随着互联网技术的飞速发展&#xff0c;Web应用的复杂度和性能要求越来越高。传统的Web开发技术&#xff0c;如JavaScript&#xff0c;虽然功能强大&#xff0c;但在处理复杂计算和高性能需求时仍存在一些局限性。WebAssembly&#xff08;简称Wasm&#xff09;作为一种…

操作系统进程管理笔记

1. 进程的基本概念 1.1 进程的定义 进程就是运行中的程序。程序本身是没有生命周期的&#xff0c;它只是存在磁盘上面的一些指令&#xff08;也可能是一些静态数据&#xff09;。是操作系统让这些字节运行起来&#xff0c;让程序发挥作用。 1.2 CPU的时分共享 操作系统通过…

Python中random库的应用

文章目录 一、random 库常用函数二、条件语句 随机数示例1&#xff1a;随机决定程序分支示例2&#xff1a;模拟概率事件 三、循环语句 随机数示例1&#xff1a;循环直到满足随机条件示例2&#xff1a;随机次数循环 四、随机操作数据结构示例1&#xff1a;随机打乱列表顺序示例…

密码学货币混币器详解及python实现

目录 一、前言二、混币器概述2.1 混币器的工作原理2.2 关键特性三、数据生成与预处理四、系统架构与流程五、核心数学公式六、异步任务调度与 GPU 加速七、PyQt6 GUI 设计八、完整代码实现九、自查测试与总结十、展望摘要 本博客聚焦 “密码学货币混币器实现”,以 Python + P…

各种各样的bug合集

一、连不上数据库db 1.可能是密码一大包东西不对&#xff1b; 2.可能是里面某个port和数据库不一样&#xff08;针对于修改了数据库但是连不上的情况&#xff09;&#xff1b; 3.可能是git代码没拉对&#xff0c;再拉一下代码。❤ 二、没有这个包 可能是可以#注释掉。❤ …

面阵相机中M12镜头和远心镜头的区别及性能优势

以下是关于面阵相机中M12镜头和远心镜头的区别及性能优势的详细分析&#xff0c;结合知识库内容整理如下&#xff1a; 一、M12镜头与远心镜头的核心区别 1. 设计原理与光学特性 特性M12镜头远心镜头光学设计标准镜头设计&#xff0c;无特殊光学校正&#xff0c;依赖传统光路。…

从内核到应用层:深度剖析信号捕捉技术栈(含sigaction系统调用/SIGCHLD回收/volatile内存屏障)

Linux系列 文章目录 Linux系列前言一、进程对信号的捕捉1.1 内核对信号的捕捉1.2 sigaction()函数1.3 信号集的修改时机 二、可重入函数三、volatile关键字四、SIGCHLD信号 前言 Linux系统中&#xff0c;信号捕捉是指进程可以通过设置信号处理函数来响应特定信号。通过信号捕捉…

DDD领域驱动与传统CRUD

DDD 是一套 应对复杂业务系统 的设计方法论&#xff0c;核心是 让代码直接映射业务逻辑&#xff0c;避免技术实现与业务需求脱节。 关键区别&#xff1a; 传统开发&#xff1a;根据数据库表写 CRUD&#xff08;技术驱动&#xff09;。DDD&#xff1a;根据业务行为建模&#xf…

20. git diff

基本概述 git diff的作用是&#xff1a;比较代码差异 基本用法 1.工作区 VS 暂存区 git diff [file]2.暂存区 VS 最新提交 git diff --staged [file] # 或 git diff --cached [file]3.工作区 VS 最新提交 git diff HEAD [file]高级用法 1.比较两个提交间的差异 git dif…

大模型面经 | 春招、秋招算法面试常考八股文附答案(五)

大家好,我是皮先生!! 今天给大家分享一些关于大模型面试常见的面试题,希望对大家的面试有所帮助。 往期回顾: 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题一) 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题二) 大模型面经 | 春招、秋招算法…

Sql刷题日志(day5)

面试&#xff1a; 1、从数据分析角度&#xff0c;推荐模块怎么用指标衡量&#xff1f; 推荐模块主要目的是将用户进行转化&#xff0c;所以其主指标是推荐的转化率推荐模块的指标一般都通过埋点去收集用户的行为并完成相应的计算而形成相应的指标数据&#xff0c;而这里的驱动…

封装 element-ui 二次弹框

author 封装 element-ui 弹框 param text 文本内容 &#xff08;不传默认显示 确定执行此操作吗&#xff1f; &#xff09; param type 弹框类型&#xff08;不传默认warning类型&#xff09; param title 弹框标题&#xff08;不传默认显示 提示 &#xff09; export fun…