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

看到一个面试题

  •  
  •   1sm23 · 2021-03-01 18:27:22 +08:00 · 5443 次点击
    这是一个创建于 1363 天前的主题,其中的信息可能已经有所发展或是发生改变。
    函数在执行之后等待 3 秒返回 1,感觉是一个 js 事件的问题,想不出来😹
    第 1 条附言  ·  2021-03-02 10:59:12 +08:00
    #19 那个能成,我就不贴出来了
    第 2 条附言  ·  2021-03-02 14:14:12 +08:00
    审题!是 return 1
    settimeout 的别往下发了啊,settimeout 加到队列里,执行栈里的东西都跑完返回出来了
    45 条回复    2021-03-11 18:41:42 +08:00
    jatai
        1
    jatai  
       2021-03-01 18:32:54 +08:00 via Android
    ..... promise, setTimeout resolve
    leopod1995
        2
    leopod1995  
       2021-03-01 19:14:02 +08:00   ❤️ 1
    ```js
    (()=>{
    setTimeout(()=> {
    return 1;
    }, 1000 *3)
    })()

    ```
    irytu
        3
    irytu  
       2021-03-01 19:26:40 +08:00 via iPhone
    至少 setTimeout 应该想出来😂
    pkupyx
        4
    pkupyx  
       2021-03-01 21:16:07 +08:00
    想起来个题还稍微复杂点:

    testFunc() {
    console.log("要求这句话立即输出",new Date());
    setTimeout(()=>{console.log("要求这句话 3 秒后输出",new Date());},1);
    // todo:要求不改动上面代码,这行后面写一段代码完成上面的需求。

    }
    autoxbc
        5
    autoxbc  
       2021-03-01 22:55:25 +08:00   ❤️ 1
    @pkupyx #4 微任务阻塞宏任务?
    // todo
    const start = new Date();
    queueMicrotask( function callee(){
      if( new Date() - start < 3000 )
       queueMicrotask(callee);
    });
    murmur
        6
    murmur  
       2021-03-01 23:03:25 +08:00
    @pkupyx 修改 console.log 的函数算么
    Kasumi20
        7
    Kasumi20  
       2021-03-01 23:21:24 +08:00   ❤️ 1
    等待 3 秒后返回 1,一定是异步的,要么返回 Promise 要么延迟传递消息

    不可能同步地卡线程 3 秒

    接下来给出一个帅气的答案:
    async function sleepSync(n) { return new Promise(resolve => setTimeout(() => resolve(), n)); }

    async function task() {
    await sleepSync(3000);
    return 1;
    }
    ericls
        8
    ericls  
       2021-03-01 23:25:51 +08:00
    这个需要写一个函数把主线程 block 3 秒,可能可以使用一些数学运算和循环之类的

    否则在 javascript 里面,很难 block 主线程
    ericls
        9
    ericls  
       2021-03-01 23:31:14 +08:00
    @Kasumi20 你这个返回的是 promise
    @leopod1995 你这个返回 undefined
    Biwood
        10
    Biwood  
       2021-03-01 23:42:41 +08:00
    @Kasumi20 #7
    我点了感谢,不过仔细想想好像也不符合题目描述,要求“返回 1”,严格来讲 async 函数返回的是 Promise 对象,而不是 1 。楼上说用 setTimeout 好像也不对,因为计时器的回调函数的返回值不是外层函数的返回值。这样看能只能用阻塞主线程,用 Date.now()计数 3 秒再返回。
    Biwood
        11
    Biwood  
       2021-03-01 23:44:14 +08:00
    function foo() {
    const start = Date.now();
    while (Date.now() - start < 3000) {}
    return 1;
    }
    Kasumi20
        12
    Kasumi20  
       2021-03-01 23:44:28 +08:00
    @ericls 敢在项目里动这种念头,你怕不是要被打屎
    ericls
        13
    ericls  
       2021-03-01 23:58:05 +08:00 via iPhone
    @Kasumi20 这个题你还能怎么解? 自己改一个 runtime?
    Kasumi20
        14
    Kasumi20  
       2021-03-02 00:01:29 +08:00   ❤️ 1
    @murmur #4

    这个可以根据变量提升原则来实现:

    console.log("要求这句话立即输出",new Date());
    setTimeout(()=>{console.log("要求这句话 3 秒后输出",new Date());},1);
    // todo:要求不改动上面代码,这行后面写一段代码完成上面的需求。

    function setTimeout(func) {
    globalThis.setTimeout(func, 3000);
    }
    1sm23
        15
    1sm23  
    OP
       2021-03-02 00:10:54 +08:00
    @leopod1995 #2 你这个一执行就返回 undefined 啦
    enchilada2020
        16
    enchilada2020  
       2021-03-02 00:13:49 +08:00 via Android
    @autoxbc 感觉这个靠谱
    gBurnX
        17
    gBurnX  
       2021-03-02 00:47:30 +08:00
    最科学的方法 ,应该是把函数调用,改为框架调用。这样你就可以在框架里,利用各种 promise 、setTimeout 了。甚至还可以加入查询进度的功能。

    简单来说,把
    A 调用函数 B,改为

    A 调用框架 B 。并且把调用过程,改为 2 个过程:
    1.A 调用框架 B,并且发送参数、处理函数与回调函数。
    2.框架 B 开始执行处理函数,执行完毕后,开发可以利用任何方法,延迟 3 秒。
    3.延迟 3 秒后,框架 B 执行回调函数来通知 A 。
    4.在 2 与 3 之间,甚至 A 还可以调用框架 B,来查询处理进度。
    akatquas
        18
    akatquas  
       2021-03-02 10:05:38 +08:00
    @leopod1995 你这返回值,被谁接住了? 谁能拿到这个返回的 1 ?
    cenbiq
        19
    cenbiq  
       2021-03-02 10:29:16 +08:00   ❤️ 5
    fun block(){
    var startAt = Date.now()
    while(true) {
    if (Date.now() - startAt >= 3000) {
    return 1;
    }
    }
    }
    zzh7982
        20
    zzh7982  
       2021-03-02 10:32:46 +08:00
    @cenbiq 同样的想法
    1sm23
        21
    1sm23  
    OP
       2021-03-02 10:59:57 +08:00
    @cenbiq 直呼牛逼
    cczeng
        22
    cczeng  
       2021-03-02 11:12:34 +08:00
    睡眠排序的兄弟?
    rodrick
        23
    rodrick  
       2021-03-02 11:24:07 +08:00
    昨天问了我怎么在代码里区分是 http1 还是 2,回来查了一下就找到一个 window.chrome.loadTimes().connectionInfo
    togou
        24
    togou  
       2021-03-02 12:28:23 +08:00
    return new Promise(r=>setTimeout(r(1),3000));
    zhuweiyou
        25
    zhuweiyou  
       2021-03-02 13:18:38 +08:00
    await new Promise(resolve => setTimeout(resolve, 3000))
    1sm23
        26
    1sm23  
    OP
       2021-03-02 13:57:23 +08:00
    @togou 不行,返回 Promise
    q673115816
        27
    q673115816  
       2021-03-02 14:56:54 +08:00
    await new Promise(resolve => setTimeout(resolve, 3000, 1))
    pkupyx
        28
    pkupyx  
       2021-03-02 15:45:17 +08:00
    卡死当前线程的都 OK,答案自己跑一下就试出来能不能过了,主要考察对 JS 线程与任务调度的理解。
    xutao881
        29
    xutao881  
       2021-03-02 15:52:48 +08:00
    。。。这个需求用来骗甲方好给自己留有优化的余地么?直接阻塞线程可还行
    shilyx
        30
    shilyx  
       2021-03-02 15:55:28 +08:00
    其实这个题在问:
    "既然你说你懂 JS,那么能否用 JS 证明你不懂 JS ?“
    cxe2v
        31
    cxe2v  
       2021-03-02 16:28:42 +08:00
    @autoxbc
    @enchilada2020
    这代码跑了,不靠谱
    autoxbc
        32
    autoxbc  
       2021-03-02 17:27:27 +08:00 via iPhone
    @cxe2v 那个代码是对 #4 题目的,不是楼主的题目
    cxe2v
        33
    cxe2v  
       2021-03-02 18:25:20 +08:00
    @autoxbc 我就是对的 4 楼的题目跑的啊,不会间隔三秒输出,我在浏览器控制台跑的
    autoxbc
        34
    autoxbc  
       2021-03-02 18:41:37 +08:00 via iPhone
    @cxe2v 那你再仔细检查一下吧,我在 firefox,vivaldi,node,deno 各跑了一次。另外为了排版,缩进那里有全角空格,要手工去掉
    libook
        35
    libook  
       2021-03-02 18:54:55 +08:00
    理论上来说,3 秒后返回 1,应该是需要阻塞线程的,否则只能立即返回 promise,然后 3 秒后接收到值。
    lwlizhe
        36
    lwlizhe  
       2021-03-02 19:22:25 +08:00
    好像 java 的类加载机制这块范例中有这种类似的,可惜这里是 js……
    djs
        37
    djs  
       2021-03-02 20:41:14 +08:00
    var fun = () => {
    var star = new Date().getTime();
    let t = new Date().getTime();
    while (t - star < 3000) {
    t = new Date().getTime();
    }
    return 1;
    };
    djs
        38
    djs  
       2021-03-02 20:41:42 +08:00
    @djs #37 我把线程阻塞掉 3s- -,不懂符不符合
    rrfeng
        39
    rrfeng  
       2021-03-02 20:53:14 +08:00
    谁给我解释一下,这不就是个 sleep(3s) 的问题吗?还是我理解错了?

    js 里没法实现 sleep 吗?
    autoxbc
        40
    autoxbc  
       2021-03-02 21:39:55 +08:00
    @rrfeng #39 js 可以 sleep,不过要用异步实现。异步的话原函数就需要先返回 promise,等 sleep 结束 resolve 出原始返回值

    而这里题目不允许修改函数返回值,也就不能异步,必须同步实现,只能用死循环阻塞住同步任务

    本质上不是问生产代码怎么写,而是加个不必要的预设,逼你用些奇技淫巧,目的是考察对任务调度的理解
    cxe2v
        41
    cxe2v  
       2021-03-02 22:09:31 +08:00
    @autoxbc 好了,我找到我的问题出在哪儿了
    dd112389
        42
    dd112389  
       2021-03-03 15:29:29 +08:00
    这个只能阻塞主线程来做吧, 异步基本都是在局部域里面, 拿不到返回值的.
    之前看过腾讯云的 cos sdk, 忘了是 v 几, 就是阻塞主线程等待对象初始化完毕.
    现在好像都改异步了.
    fy136649111
        43
    fy136649111  
       2021-03-03 16:02:44 +08:00
    还可以这样
    function sleep(){
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 3000);
    }
    fy136649111
        44
    fy136649111  
       2021-03-03 16:04:14 +08:00
    @fy136649111 function sleep(){
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 3000);
    return 1;
    }
    zeni123
        45
    zeni123  
       2021-03-11 18:41:42 +08:00
    @cenbiq 是让用户等待三秒然后返回 1 哈哈哈 真等待 任何东西都要等待 不含糊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2918 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 00:15 · PVG 08:15 · LAX 16:15 · JFK 19:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.