第一题:以下代码输出什么,为什么?
KieSun opened this issue · comments
try {
(async function() { a().b().c() })()
} catch (e) {
console.log(`执行出错:${e.message}`)
}
第一反应答案是什么?为什么会这样报错?
新建了一个大厂真题每日打卡群,有意愿学习打卡的再进,群已达扫码上线,请加好友拉你进群。
Fucking Awesome !
- VM404:2 Uncaught (in promise) ReferenceError: a is not defined
- a 函数未定义,
a is not defined
- try catch 无法捕获异步错误
- async 是 Generator 生成器的语法糖,会报发生在
in Promise
错误
a is not defined
ReferenceError: a is not defined
a 都没有定义
ReferenceError: a is not defined
try catch 无法捕获异步错误
a is not defined
a is not defined
async 约等于 Promise
执行try中语句时报错ReferenceError: a is not defined
,因此catch也捕获不到错误。
ReferenceError: a is not defined
ReferenceError: a is not defined
(async function() {a().b().c() })()是个异步任务,try...catch无法捕捉,所以不会执行catch中的console
改成
try {
await (async function() { a().b().c() })()
} catch (e) {
console.log(`执行出错:${e.message}`)
}
就可以catch啦执行出错:a is not defined
执行a()时,因为a未定义,所以会报错
但因为try里面async是异步,所以不会被同步的catch捕获,即不会有console输出
最终会返回一个rejected的Promise, 所以报的错为 Uncaught (in promise) ReferenceError: a is not defined
a is not defined
ReferenceError: a is not defined
async定义的是异步任务,catch无法捕获
如果有异步函数的话,就不需要用try catch 了
ReferenceError: a is not defined;
try执行,async方法出错,相当于promise reject,错误没被catch捕获
what‘s the fuck you doing here?
至于为啥catch 没有捕捉到,楼上很多的人都没有解释很清楚,我来回答一下我的陋见:
async + function 返回的是一个promise,promise 在自执行(FFEE)的一个作用域中是个完整的异步函数自执行了,内层函数已经执行完了,外层当然catch 不到。
想要被catch ,是在try 中发生了错误,代码中断。而一个完整promise只会在自身这一层被捕获,外面认为你这是自己的事,不能管啊。出来闹,我就管!
try catch 不能捕获异步代码。 所以也不是单纯的考量promise吧。虽然他也属于异步
1.try catch捕获不到该错误
2.按照正常语法来说 错误应该是 ReferenceError类型 a is not defined
3.可以修改一下 加一个await关键字 获取promise的返回值,使其能够被捕获到
4.也可以直接使用promise自带的catch捕获错误 (与题目无关了)
1.try里面是一个自执行的async函数,async是异步的方法,try catch没办法捕获到异步方法
2.async函数返回的是promise,因为内部发生了错误,所以变成promise rejected了,错误则是a方法未定义
个人见解: try catch是同步的,而async是异步的,返回的是一个Promise。而try catch只能捕获到同步函数中的异常,无法捕获到异步函数中的异常错误。而async中执行的,a().b().c(),一开始的a就会报错,因为a未定义。报错为:Uncaught ReferenceError: a is not defined
at :1:1
我又要来提灵魂之问了?为啥try catch 不能捕获异步任务的error ,这跟浏览器的执行机制(事件循环)有关:
try catch 作为宏任务而promise是微任务,当执行promise.then(()=>callbaclk()),进入回调函数的时候,外层try catch 这个宏任务已经出栈了,跟他已经没有关系了
- ReferenceError: a is not defined
- 执行异步方法a().b().c()的时候 try catch已经出栈执行完毕
给出2个例子 方便理解
// 异步,宏任务
try {
setTimeout(function() {
console.log(b);
}, 0);
} catch (error) {
console.log('error', error); // 这里是不会执行的
}
console.log('out try catch')
// 异步,微任务
try {
new Promise(() => {
throw new Error('new promise throw error');
});
} catch (error) {
console.log('error', error);
}
原因是因为:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言,比如 promise,promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。
try {
let a = 0
;(async function() {
a += 1
console.log('inner', a)
throw new Error('123')
// a()
})()
console.log('outer', a)
} catch(e) {
console.warn('Error', e)
}
这段代码,inner 会在 outer 之前输出,为啥?
ReferenceError: a is not defined
try catch正常来说是可以捕获到错误的,但是由于try里面的是异步任务;try catch作为宏任务,在函数执行的时候就已经入栈,而当异步函数抛出异常时,try catch已出栈
try { let a = 0 ;(async function() { a += 1 console.log('inner', a) throw new Error('123') // a() })() console.log('outer', a) } catch(e) { console.warn('Error', e) }这段代码,inner 会在 outer 之前输出,为啥?
promise是异步。 throw new Error('123')的时候错误被promise.reject接收,然后继续执行同步代码,等同步代码执行完执行异步爆出这个错误
try { let a = 0 ;(async function() { a += 1 console.log('inner', a) throw new Error('123') // a() })() console.log('outer', a) } catch(e) { console.warn('Error', e) }这段代码,inner 会在 outer 之前输出,为啥?
本人补充一下,为啥要等 outer 输出完后,再抛错
ReferenceError: a is not defined
(async function() {a().b().c() })()是个异步任务,try...catch无法捕捉,所以不会执行catch中的console
改成try { await (async function() { a().b().c() })() } catch (e) { console.log(`执行出错:${e.message}`) }就可以catch啦
执行出错:a is not defined
老哥,你是第一位给出完整答案的,如果需要简历修改服务可以发我邮箱:zx597813039@gmail.com
ReferenceError: a is not defined
- 立即执行(async function() {a().b().c() })()。因为返回是一个promise,所以返回一个promise.reject
- 执行完接下来的同步任务,这时候执行完try...catch
- 执行promise.reject,报错
感觉上述的答案并不对。
从 async/await 的语法糖实现来看,题中的 async 函数是放在new Promise(executorFunc)
的executorFunc
函数中执行的,众所周知executorFunc
是立即执行,所以不存在什么异步任务。
而错误为什么不被 try/catch 捕获,是因为 Promise 在实例化的时候会捕获executorFunc
的错误,所以外面是捕获不到的。
感觉上述的答案并不对。
从 async/await 的语法糖实现来看,题中的 async 函数是放在new Promise(executorFunc)
的executorFunc
函数中执行的,众所周知executorFunc
是立即执行,所以不存在什么异步任务。
而错误为什么不被 try/catch 捕获,是因为 Promise 在实例化的时候会捕获executorFunc
的错误,所以外面是捕获不到的。
我感觉你说的才是正确的,我昨天也是第一次知道Promise中的错误不会被抛到外部了。然后搜索一圈,就找到这么一篇文章翻译自V8引擎作者的文章 从JS引擎理解Await b()与Promise.then(b)的堆栈处理 。虽然不是和本次题目强关联,但也是在Promise与堆栈方面带给我所不知道的一面
try {
let a = 0
;(async function() {
a += 1
console.log('inner', a)
throw new Error('123')
// a()
})()
console.log('outer', a)
} catch(e) {
console.warn('Error', e)
}
如上代码,他是能够输出'outer' 1 的 ; try catch认为你这段代码没有错,所以进不了catch。Promise内部的错误应该在Promise中解决。
我想请教你有没有相关文章能够佐证这个观点。
;(function(){
let p
try {
let a = 0
p=Promise.resolve(1).then(e=>a())
console.log('outer', a)
} catch(e) {
console.warn('Error', e)
}
setTimeout(()=>{
p.catch(e=>{console.warn(e)})
},1000)
})()
然后我有这么一段代码,我惊奇的发现chrome控制台会在1s后把错误输出给吞回去;输出warnning。
这是什么原理
感觉上述的答案并不对。
从 async/await 的语法糖实现来看,题中的 async 函数是放在new Promise(executorFunc)
的executorFunc
函数中执行的,众所周知executorFunc
是立即执行,所以不存在什么异步任务。
而错误为什么不被 try/catch 捕获,是因为 Promise 在实例化的时候会捕获executorFunc
的错误,所以外面是捕获不到的。我感觉你说的才是正确的,我昨天也是第一次知道Promise中的错误不会被抛到外部了。然后搜索一圈,就找到这么一篇文章翻译自V8引擎作者的文章 从JS引擎理解Await b()与Promise.then(b)的堆栈处理 。虽然不是和本次题目强关联,但也是在Promise与堆栈方面带给我所不知道的一面
try {
let a = 0
;(async function() {
a += 1
console.log('inner', a)
throw new Error('123')
// a()
})()
console.log('outer', a)
} catch(e) {
console.warn('Error', e)
}
如上代码,他是能够输出'outer' 1 的 ; try catch认为你这段代码没有错,所以进不了catch。Promise内部的错误应该在Promise中解决。
我想请教你有没有相关文章能够佐证这个观点。;(function(){
let p
try {
let a = 0
p=Promise.resolve(1).then(e=>a())
console.log('outer', a)
} catch(e) {
console.warn('Error', e)
}
setTimeout(()=>{
p.catch(e=>{console.warn(e)})
},1000)
})()
然后我有这么一段代码,我惊奇的发现chrome控制台会在1s后把错误输出给吞回去;输出warnning。
这是什么原理
这种问题其实其实查标准就好了:
内部 throw 被 promise reject
了,外部就不可能捕获到这个错误,当然不管有没有这个机制都是捕获不到的,毕竟异步代码怎么让同步代码捕获错误。
如上图,从 ECMA-262 的27.7.5.1 AsyncFunctionStart
一节来看,async 函数是立即执行的,执行结果出现异常时reject
- Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution context the following steps will be performed:
a. Letresult
be the result ofevaluating asyncFunctionBody
.
...
d. If result.[[Type]] is normal, then
i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
e. Else if result.[[Type]] is return, then
i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « result.[[Value]] »).
f. Else,
i. Assert: result.[[Type]] isthrow
.
ii. Perform ! Call(promiseCapability.[[Reject
]], undefined, « result.[[Value]] »).
g. Return.
至于第二个问题,众所周知当 Promise 异常未被捕获时,会报Uncaught (in promise) TypeError
,翻了下 ECMA-262 好像没有明确规定,延迟捕获异常要怎么办。Chrome 会吞回去,Firefox 并不会,大概是自行发挥的结果吧。
@cn1001wang
@ambit-tsai @KieSun 感谢二位, execution context stack 我还得再研究研究 !
try{
(async function(){
await a().b().c()
})()
}catch(e){
console.log(e,'报错原因-------')
}
1 首先 try catch (同步)异常 报错 会执行 catch
2 async 是一个promise 语法糖 返回一个 promise
3 在 async 执行栈中 a b c 3个方法
4 在执行a的时候 会直接报错 a is nodefind
5 async 会返回 promise 其实在这里应该是有一个错误 但是 浏览器 读取到 a方法的错误, 到此为止 在不考虑任何因素的情况下 同步的捕获异常 肯定是捕获不到异步的方法里面的问题。
a is not defined
try {
(async function() { a().b().c() })()
} catch (e) {
console.log(`执行出错:${e.message}`)
}
- 执行出现异常 Uncaught (in promise) ReferenceError: a is not defined
- try catch 无法捕获异常
游览器会抛出异常 a is not defined
因为try catch无法捕获异步方法中的错误
- 执行结果 Uncaught (in promise) ReferenceError: a is not defined
- try catch 无法捕获异常
- 需要看看大佬们的见解,我理解的不透测
个人觉得这道题考察的是 async 函数执行出错时语言层面是怎么处理的,而不是异步导致 try catch 无法捕获错误。(async function() { a().b().c() })() 并没有涉及到异步。
@ambit-tsai 的解释比较靠谱
- 结果为
Uncaught (in promise) ReferenceError: a is not defined
try catch
是同步代码,无法捕捉异步代码中的错误- 在 async 中,执行了未定义的 a(),因此这时候的错误被
Promise.reject
捕捉