当前位置: 首页 > web >正文

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

两天更新完。

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.xdnf.cn/news/1550.html

相关文章:

  • 【FAQ】PCoIP 会话后物理工作站本地显示器黑屏
  • 60个GitLab CI/CD 面试问题和答案
  • Ubuntu 一站式部署 RabbitMQ 4 并“彻底”迁移数据目录的终极实践
  • 2025.04.24【3D】3D绘图入门指南
  • 直接偏好优化(Direct Preference Optimization,DPO):论文与源码解析
  • playwright 免API实现kimi聊天机器人
  • 题解:CF2072F Goodbye, Banker Life
  • 经颅超声刺激设备的技术指标简析
  • vue3:十一、主页面布局(修改顶部导航栏样式-右侧:用户信息+退出登录+全屏显示)
  • 【计算机视觉】CV实战项目 - 基于YOLOv5与DeepSORT的智能交通监控系统:原理、实战与优化
  • C# 音频分离(MP3伴奏)
  • 人脸识别考勤系统实现教程:基于Face-Recognition、OpenCV与SQLite
  • 【Yii2】Yii2框架的一次BUG排查
  • 【KWDB 创作者计划】_嵌入式硬件篇---寄存器与存储器截断与溢出
  • 2025 年免费 Word 转 PDF 转换器有哪些?
  • 【RocketMq源码篇-01】环境搭建、基本使用、可视化界面
  • Java中正则表达式使用方法
  • Java发展史及版本详细说明
  • JVM性能优化之老年代参数设置
  • 深入浅出学会函数(上)
  • ArcGIS Pro跨图层复制粘贴
  • mongo客户端操作mongodb记录
  • 【Python爬虫实战篇】--Selenium爬取Mysteel数据
  • 堆和二叉树--数据结构初阶(3)(C/C++)
  • K8S学习路线图:从入门到精通的技术成长指南
  • STM32 串口USART
  • unity使用iTextSharp生成PDF文件
  • AI时代的能力重构与终身进化
  • 1.1 java开发的准备工作(入门)
  • day4 pandas学习