V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
autoxbc
V2EX  ›  JavaScript

如果你自认熟悉 async...await,来猜一下这个代码的运行结果

  •  
  •   autoxbc · 2021-07-13 14:02:49 +08:00 · 5698 次点击
    这是一个创建于 990 天前的主题,其中的信息可能已经有所发展或是发生改变。

    姐妹篇
    如果你自认熟悉 Promise,来猜一下这个代码的运行结果

    要用猜的,别偷偷用浏览器运行

    const Err = async () => {
    	throw new Error(42);
    };
    
    const Obj = {
    	async A (){
    		try {
    			return Err();
    		} catch {
    			console.log('A');
    		}
    	},
    	async B (){
    		try {
    			await Err();
    		} catch {
    			console.log('B');
    		}
    	},
    	async C (){
    		try {
    			Err();
    		} catch {
    			console.log('C');
    		}
    	},
    };
    
    ( async () => {
    	for( const key in Obj )
    	{
    		try {
    			await Obj[key]();
    		} catch {
    			console.log('D');
    		}
    	}
    } )();
    
    第 1 条附言  ·  2021-07-13 20:32:38 +08:00
    1. 这是标准的异步函数错误捕获,可不是茴字写法什么的
    2. 回复中已经有朋友认真解答知识点,这题的目的达到了
    35 条回复    2021-07-14 12:37:46 +08:00
    meeop
        1
    meeop  
       2021-07-13 14:06:54 +08:00   ❤️ 23
    既然还要猜,说明代码不清晰,可读性差,重写吧
    binux
        2
    binux  
       2021-07-13 14:09:36 +08:00 via Android
    DBD
    Zeffon
        3
    Zeffon  
       2021-07-13 14:12:58 +08:00
    DB 吧
    mxT52CRuqR6o5
        4
    mxT52CRuqR6o5  
       2021-07-13 14:15:23 +08:00
    想了一遍是 DB,运行一遍确实是 DB,不难啊
    binux
        5
    binux  
       2021-07-13 14:16:53 +08:00 via Android
    @mxT52CRuqR6o5 哦,B 没 rethrow,大意了
    mxT52CRuqR6o5
        6
    mxT52CRuqR6o5  
       2021-07-13 14:18:43 +08:00
    这个异常处理弄明白就行了,那个姐妹篇弄不明白也没关系
    ayase252
        7
    ayase252  
       2021-07-13 14:20:58 +08:00   ❤️ 3
    D
    B
    unhandled promise rejection
    Jirajine
        8
    Jirajine  
       2021-07-13 14:25:43 +08:00 via Android
    这就是为什么使用异常进行错误处理很糟糕,会把控制流搞得混乱。
    如果所有错误都用 Promise<value|error>的形式返回,一眼就能看出来。
    ericgui
        9
    ericgui  
       2021-07-13 14:26:35 +08:00
    这算是茴字的几种写法嘛
    xiangyuecn
        10
    xiangyuecn  
       2021-07-13 15:08:03 +08:00   ❤️ 2
    感觉:for in object 是一个玄学,应该不是有序的,大部分时候测试不出问题

    就像 HashMap 一样,大部分测试的时候是按 put 的顺序,就是不给你看到问题的机会
    ochatokori
        11
    ochatokori  
       2021-07-13 15:40:02 +08:00 via Android
    什么嘛,原来我对 promise 还挺熟悉的
    learningman
        12
    learningman  
       2021-07-13 15:45:07 +08:00
    @Jirajine #8 等下就有人骂你 if err!=nil
    mcfog
        13
    mcfog  
       2021-07-13 16:54:06 +08:00 via Android   ❤️ 2
    做这种人肉 v8 题做不出来也无所谓
    如果给结果要求解释讲不清楚就不行了
    但基本上很多人是能够讲个大概的,没什么区分度

    所以我不太喜欢面试被问到这类,也不会自己在面试中问这类问题
    RockShake
        14
    RockShake  
       2021-07-13 16:58:11 +08:00
    怎么感觉输出是在骂人
    Huelse
        15
    Huelse  
       2021-07-13 17:07:35 +08:00
    作为前端新手经验:await 才“执行”
    libook
        16
    libook  
       2021-07-13 17:08:55 +08:00   ❤️ 10
    这个掌握两个原理就行:
    1. async 函数返回 Promise ;
    2. Promise 只有被取值才能捕捉到错误,所以要么 Promise.prototype.catch(),要么就用 await+try/catch 。

    A 部分 Err()返回的是个 Promise,所以 try 不做不到错误,return 出去之后在主函数里 await,就取到了这个错误,被主函数的 try 捕捉到,输出 D 。

    B 部分 Err()返回 Promise,被 await 取到错误,被 B 的 try 捕捉到,输出 B 。

    C 部分 Err()返回 Promise,C 的 try 捕捉不到错误,因为 C()返回的是一个 undefined,所以主函数的 try 也捕捉不到这个错误,于是这一次循环什么都没输出。
    但是可能 JS 引擎会提示有一个 Uncaught 的异常,这个得看 JS 引擎的策略,有的引擎不提示,提示的话如果还输出 message 的话就会输出 42 。
    GiantHard
        17
    GiantHard  
       2021-07-13 18:22:19 +08:00 via Android   ❤️ 8
    如果你自认熟悉 js 类型转换,来猜一下这个代码的运行结果

    ```
    [!+[]+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]
    ```

    要用猜的,别偷偷用浏览器运行
    MichealXie
        18
    MichealXie  
       2021-07-13 18:36:35 +08:00
    上次去面试遇到这种猜输出结果的, 心里暗暗在骂, 我自己面试别人重来不出这种题
    togou
        19
    togou  
       2021-07-13 18:38:11 +08:00
    写的太恶心了 直接 for await of [a(),b(),c()] 嘛
    mxT52CRuqR6o5
        20
    mxT52CRuqR6o5  
       2021-07-13 18:48:21 +08:00 via Android
    @xiangyuecn 新版 es 标准规定了 for in 遍历的顺序,是固定的,旧版 chrome 里 for in 的顺序和你具体的代码有关
    Jirajine
        21
    Jirajine  
       2021-07-13 19:07:41 +08:00 via Android
    @learningman 不用等人,我自己就是 go 黑。这里我想说的是 union type 。
    mx1700
        22
    mx1700  
       2021-07-13 20:55:00 +08:00 via Android   ❤️ 1
    这题出的挺好,不知道为什么楼上一些人不认同
    Actrace
        23
    Actrace  
       2021-07-13 21:20:49 +08:00   ❤️ 2
    @mx1700 因为如果工作中写这种代码的同事可能会被打断腿。
    muzuiget
        24
    muzuiget  
       2021-07-13 21:50:13 +08:00
    for( const key in Obj ) 不保证顺序吧,所有情况都有可能。
    dorr
        25
    dorr  
       2021-07-13 21:50:49 +08:00
    @mx1700 可读性太差了,维护的同事会打人的
    Biwood
        26
    Biwood  
       2021-07-13 22:05:14 +08:00 via iPhone
    把最后的 for…in 改成数组遍历更严谨一些,16 楼正解

    另外,感觉 async 关键字现在很容易被滥用,就说你这个题里面,除去包含 await 操作的函数,其他几个函数根本就不需要用到 async
    no1xsyzy
        27
    no1xsyzy  
       2021-07-14 09:44:14 +08:00
    await 会把 Promise<Promise<X>> 直接返回到 X 还行……
    finalwave
        28
    finalwave  
       2021-07-14 10:24:03 +08:00
    @no1xsyzy async 里返回 Promise 的时候就自动把 Promise<Promise<X>>解成 Promise<X>了,不是 await 这一步干的
    no1xsyzy
        29
    no1xsyzy  
       2021-07-14 10:34:48 +08:00
    @finalwave async 还这么做?我试了一下 await new Promise(r=>r(new Promise(r=>r(1))) 也这样应该是在 Promise 里面完成的?
    也就是说实际上不可能构造出 Promise<Promise<X>>?
    Email
        30
    Email  
       2021-07-14 10:46:42 +08:00
    蒙古上单 不请自来
    libook
        31
    libook  
       2021-07-14 11:20:33 +08:00   ❤️ 1
    @xiangyuecn #8
    @mxT52CRuqR6o5 #18
    @muzuiget #22

    关于顺序可以参考 ECMA-262 2022 的这个规范: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
    我看 ES6 的时候就是这样了,只不过章节名有变: https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
    ES5.1 内容变化太大,没工夫看,有人看过可以发一下情况。

    翻译过来大义就是:
    1. 对象的属性如果可以被当做“array index”(如是数字或只包含数字的字符串)的话,就按照索引数值升序排序;
    2. 其他情况按照属性的创建时间升序排序。

    JS 的解析是按照代码自上而下的,所以题主给的这个代码的顺序是固定的,不会在执行中变化。
    Marszm
        32
    Marszm  
       2021-07-14 11:32:32 +08:00
    如果生产代码写成这样。。。出 bug 了,写个这个要被拉出来打一顿。。看到都气人。
    我写代码追究一个原则,简单明了偷懒。能少判断绝对少判断,能不重复写的代码绝不重复写。
    Marszm
        33
    Marszm  
       2021-07-14 11:36:57 +08:00
    再说一个点。。。async...await,promise,他们出现的原因就是 JS 的硬伤回调地狱。。为了简化复杂逻辑流而搞出来的语法糖。。然后你们面试想办法把一个简化代码复杂度的玩意搞的贼复杂。有自虐倾向对吧。。
    不过我也认同,还是要明白其中的原理。但是真的面试能不出这种题么。谁平时代码写成这样?
    yzqtdu
        34
    yzqtdu  
       2021-07-14 12:05:52 +08:00
    这个问题对我还是蛮有意义的。除了上面大家总结的几点,我觉得这里还体现了 JS 里 Promise 对错误的处理,即 Promise 会“吞噬”传入函数的异常错误( http://jamesknelson.com/are-es6-promises-swallowing-your-errors/),并不会像普通函数一样,直接终止执行并解栈。当事件循环执行队列任务时,如果该 promise 对象之前执行过 catch 或 then 调用,新创建的 promise 才会异步执行传入函数,所以在 catch 里 throw 也是没法被外部捕获的,因为之前的执行栈已经解开了( https://stackoverflow.com/questions/30715367/why-can-i-not-throw-inside-a-promise-catch-handler
    daguaochengtang
        35
    daguaochengtang  
       2021-07-14 12:37:46 +08:00   ❤️ 1
    @Actrace
    @dorr 人家出这题目本来就为了考察对知识点的掌握情况吧,出题本来不就应该是高度抽象考察对概念的理解吗,也没人说工作中会这样写啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2760 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 12:10 · PVG 20:10 · LAX 05:10 · JFK 08:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.