JS 异步(下)部分面试题分析
程序员文章站
2024-03-24 23:18:52
...
JS 异步(下)部分面试题分析
4.promise 中 then 和 catch 的连接
4.1 第一题
Promise.resolve().then(() => {
console.log(100);
}).catch(() => {
console.log(200);
}).then(() => {
console.log(300);
});
输出:100,300
分析:
- 因为执行的是 promise 的 resolve 函数,则触发第一个 then ,由此执行第 3 行,输出 100;
- 第一个 then 在执行后,未抛出错误,则不会触发最近的 catch,会直接触发最近的 then ,则执行第 7 行 ,输出 300;
4.2 第二题
Promise.resolve().then(() => {
console.log(400);
throw new Error('error1')
}).catch(() => {
console.log(500);
}).then(() => {
console.log(600);
});
输出:400,500,600
分析:
- 因为执行的是 promise 的 resolve 函数,则触发第一个 then ,由此执行第 3 行,输出 400;
- 第一个 then 在执行后,抛出错误,触发最近的 catch,执行第 6 行 ,输出 500
- 在 catch 中未抛出异常,则会触发紧邻的 then ,即执行第 8 行,输出 600;
注:关于第 3 点,不理解的可以再看看 JS 异步进阶 5.3 节 第 5 点的 then 和 catch 对状态的影响
4.3 第三题
Promise.resolve().then(() => {
console.log(700);
throw new Error('error2')
}).catch(() => {
console.log(800);
}).catch(() => {
console.log(900);
});
输出:700,800
分析:
- 因为执行的是 promise 的 resolve 函数,则触发第一个 then ,由此执行第 3 行,输出 700;
- 第一个 then 在执行后,抛出错误,触发紧邻的 catch,执行第 6 行 ,输出 800
- 在 catch 中未抛出异常,则只会触发紧邻的 then,不会触发catch ;
4.4 附加题:将上面三个 promise 放在一起执行,给出输出结果
Promise.resolve().then(() => {
console.log(100); // 1
}).catch(() => {
console.log(200);
}).then(() => {
console.log(300); // 6
});
Promise.resolve().then(() => {
console.log(400); // 2
throw new Error('error1')
}).catch(() => {
console.log(500); // 4
}).then(() => {
console.log(600); // 7
});
Promise.resolve().then(() => {
console.log(700); // 3
throw new Error('error2')
}).catch(() => {
console.log(800); // 5
}).catch(() => {
console.log(900);
});
// 100,400,700,500,800,300,600
分析:
- 按顺序,第 1,9, 18行首先执行 resolve 函数,then 函数依次进入微任务队列(第一梯队),随后根据微任务队列顺序执行;
- 执行第 2 行,输出 100,触发第 5 行 then,进入微任务队列等待执行(第二梯队);
- 执行第 10 行,输出 400,抛出异常,触发第 12 行 catch ,等待第一梯队微任务执行完就马上执行;
- 执行第 19 行,输出 700,抛出异常,触发第 24 行 catch ,等待第一梯队微任务执行完就马上执行;
- 第一梯队任务执行完,依次触发 12,24 行 cath ,输出 500, 800,注意,触发完 12 行 catch 后,触发第 14 行 then,进入微任务队列(第二梯队);
- 按顺序执行第二梯队微任务,输出 300 ,600;
5.async 和 await 语法题
5.1 第一题
async function fn() {
return 100;
};
async function excute() {
const res1 = fn();
const res2 = await fn();
console.log('res1:', res1);
console.log('res2:', res2);
}
excute(); // res1, res2 的内容
输出:res1: Promise {: 100}
res2: 100
分析:
- 直接执行 async 函数,会返回一个 Promise 对象;
- await 相当于 promise 的then(不会走catch), 返回的是then的参数,处理的是成功的情况
5.2 第二题
async function excute() {
console.log('start');
const res1 = await 100;
console.log('res1:', res1);
const res2 = await Promise.resolve(200)
console.log('res2:', res2);
const res3 = await Promise.reject(300)
console.log('res3:', res3);
console.log('end');
}
excute();// 打印内容
输出:
start
res1: 100
res2: 200
Uncaught (in promise) 300
分析:
- await 加数据类型,直接返回该数据类型的值;
- await 相当于 promise 的 then,返回的是 then 的参数,即200
- Promise.reject,抛出错误,程序停止执行
6. promise 和 setTimeout 的顺序
console.log(100);
setTimeout(() => {
console.log(200);
}, 0);
Promise.resolve().then(() => {
console.log(300);
});
console.log(400);
输出:100,400,300,200
分析:
- 首先执行第 1 行,输出 100;
- 执行到 setTimeout ,放进 web APIs 开始计时,完成计时后就放进任务队列等待执行;
- 执行到 Promise.resolve,触发第 1 个 then,放进微任务队列等待执行;
- 执行第 6 行,输出 400;
- 轮询微任务队列,执行第 6 行,输出 300;
- 轮询任务队列,执行第 3 行,输出 200;
7.promise 和 async / await 的顺序问题
async function asyncFn1() {
console.log('asyncFn1 excute');
await asyncFn2();
console.log('asyncFn1 end');
}
async function asyncFn2() {
console.log('asyncFn2 excute');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
});
asyncFn1();
new Promise ((resolve) => {
console.log('promise excute');
resolve();
}).then(() => {
console.log('then excute');
});
console.log('script end');
输出:
script start
asyncFn1 excute
asyncFn2 excute
promise excute
script end
asyncFn1 end
then excute
setTimeout
分析:
- 首先执行第 11 行,输出 script start;
- 执行到第 13 行 setTimeout,放入 web APIs 中开始计时,计时完成放进任务队列;
- 执行第 17 行 asyncFn1 函数,进入 asyncFn1 函数;
- 执行第 2 行,输出 asyncFn1 excute;
- 执行第 3 行 asyncFn2 函数,进入 asyncFn2 函数,第 4 行进入微任务队列等待执行(这是因为在 await 后面执行的代码,都可以看作是 await 后的异步代码(微任务),需要等待同步执行完后才能执行)
- 执行第 8 行,输出 asyncFn2 excute;,退出 asyncFn2 函数,退出 asyncFn1 函数;
- 执行第 19 行 promise,直接执行第 20 行,输出 promise excute;第 22 行进入微任务队列;
- 执行第 26 行,输出 script end;
- 轮询微任务队列,按顺序依次输出 asyncFn1 end,then excute;
- 轮询任务队列,执行第 14 行,输出 setTimeout;
至此,程序执行结束。
欢迎大家点赞,收藏,关注!!!
上一篇: vue项目笔记(29)-组件显示的动画
下一篇: JavaScript命名空间