V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Juggernaut
V2EX  ›  Node.js

node.js 支持函数作为参数注册回调函数,彰显其支持异步处理特性

  •  
  •   Juggernaut · 2017-12-10 16:09:27 +08:00 · 3995 次点击
    这是一个创建于 2322 天前的主题,其中的信息可能已经有所发展或是发生改变。
    C 也同样支持函数可以作为参数注册回调,而且检查严格,node.js 根本不作检查,等运行就 crash·

    有木有同感
    27 条回复    2017-12-12 14:42:12 +08:00
    bramblex
        1
    bramblex  
       2017-12-10 16:19:48 +08:00 via iPhone
    Diss nodejs 你至少拿 c 艹 11 的 lambda 吧…
    zjcqoo
        2
    zjcqoo  
       2017-12-10 16:34:23 +08:00
    typescript 欢迎你
    Juggernaut
        3
    Juggernaut  
    OP
       2017-12-10 16:34:34 +08:00
    @bramblex 倒不是 diss,node.js 新手,之前只有 C 相关经验,学习的过程中有些疑惑,所以来交流交流;
    node.js 标榜异步处理,我现在的理解就是注册回调,把那些耗费时间的处理扔到回调函数里面去处理,不要阻塞 node.js 处理的单线程即可,其实工作还是在那,只不过是谁(线程)来处理的问题,node.js 很取巧的把重活累活都扔给别人了…是不是可以这样理解?

    多谢大侠讨论
    bramblex
        4
    bramblex  
       2017-12-10 16:43:37 +08:00 via iPhone
    @Juggernaut

    如果你只有 c 基础的话,那你首先要理解的在一门函数式语言里面,一个函数和一个 int 或者一个 string 是一样的东西,可以在运行时被创建,被传递。

    函数作为参数不是什么新奇的操作,所有语言都能这么干,重点的一个函数能接受函数作为参数并且能返回一个全新的函数。

    接下来再讲讲异步。

    在 jsruntime 里面
    snnn
        5
    snnn  
       2017-12-10 16:46:48 +08:00 via Android
    光一个函数怎么做回调啊。还得有 context。
    codehz
        6
    codehz  
       2017-12-10 16:47:52 +08:00
    C 函数不支持闭包
    ObjC 的一个扩展倒是可以支持闭包
    bramblex
        7
    bramblex  
       2017-12-10 16:48:04 +08:00 via iPhone
    在 js runtime 里面,永远都有且只有一条线程在执行 js 代码。worker 之类的情况先不讲。

    所以只要是用 js 写的代码,不管你写在哪里,只要是 js,一旦阻塞,那整个程序都会阻塞。

    不会阻塞的是提供的 api 不会阻塞。
    bramblex
        8
    bramblex  
       2017-12-10 16:53:57 +08:00 via iPhone
    @snnn c 里强行靠指针和全局变量来回调的,至少折腾 moogose 的时候着实被恶心了一次。
    BOYPT
        9
    BOYPT  
       2017-12-10 17:06:10 +08:00
    一般 node 里面不是为了回调而回调,而是因为涉及异步 io。
    Juggernaut
        10
    Juggernaut  
    OP
       2017-12-10 17:19:31 +08:00 via iPhone
    @bramblex 感谢🙏
    1、函数在运行时被创建,这个该如何理解? c 的函数调用也是运行时创建,离开后销毁;
    2、js 处理由一个线程负责,js 处理阻塞了该线程也就阻塞了,这个理解,你说的 API 不阻塞是什么意思,无法体会…
    再次感谢
    momomirage
        11
    momomirage  
       2017-12-10 17:24:41 +08:00
    你既然学过 c, 可以对比一下: c 的函数本身都是静态分配的, 编译好即使不运行, 用 nm 也可看到.

    相对地, 你可以考虑一下纯 c 怎么实现一个 Function.prototype.bind
    SuperMild
        12
    SuperMild  
       2017-12-10 17:54:56 +08:00
    1. 别的语言当然也会用自己的方法实现异步,只是在 Node 里写异步更轻松一些
    2. 动态语言、鸭子语言当然是在运行时才“检查”的(也不是检查,就是实在运行不了 crash ),想更严格地提前检查就用别的办法(办法有很多)。这有坏处也有好处,世事没有完美。
    secondwtq
        13
    secondwtq  
       2017-12-10 18:34:36 +08:00   ❤️ 1
    node 这个所谓的回调学名叫 CPS

    异步( asynchronous )可以简单理解为领导安排下去一个事情,然后就不用管了,等到下面干完了再通知回来
    典型栗子是 OS 的中断机制,也可以说基于中断的 IO 本身就是异步的
    至于处理是否“耗费时间”,还有线程什么的,站在异步的角度都属于 implementation detail,异步就是指上面那个机制

    非阻塞( non-blocking )直观理解就是 POSIX API 里面的 fcntl(fd, F_SETFL, O_NONBLOCK),区别是 read 和 write 调用立即返回,但不一定成功(返回值会 indicate 这个状态),放到 node 里面就是 fs.readFile 这种在它自己的函数里面是立即返回的
    这个东西玩过 nginx 之类的应该明白

    这些 term 的区别是很微妙的
    wwqgtxx
        14
    wwqgtxx  
       2017-12-10 20:06:47 +08:00 via iPhone
    @Juggernaut 区别在于 c 的函数是在编译期间就生成的,而 js 的函数在运行时被执行到定义语句的时候才被创建,而且类似于 js/python 这类语言的函数本质上都是一个对象,所以可以在一个函数中动态创建一个新的函数作为返回值
    leekafai
        15
    leekafai  
       2017-12-10 22:55:23 +08:00 via Android
    支持楼主转 java
    esw
        16
    esw  
       2017-12-10 23:27:32 +08:00   ❤️ 1
    感觉题主没明白 node 异步的本质

    js 核心主要分两部分:v8 和 libuv,v8 用来解释 js 代码本身

    libuv 用来支持异步操作,例如创建定时器,发送网络请求等等

    libuv 实际上是用 c 写的事件循环框架,支持 c 以回调的方式运行。所以通过 libuv 结合 v8 写出一下常用操作的 binding (定时器,网络,文件等),node 就支持了异步。

    关于 libuv,可以参考 http://docs.libuv.org/en/v1.x/
    cctv1005s927
        17
    cctv1005s927  
       2017-12-11 00:00:03 +08:00
    @Juggernaut 在 NodeJS 中不阻塞的 API 通常由原生方法,或者基于原生方法构建的 API,最简单的例子就是 fs.readFile,或者是 HTTP 相关的 API,在 node 层来看是不阻塞的,通过回调函数来告知过程结束。nodejs 下面还有一个 libuv,libuv 会创建线程的,但是这一层不是由 js 来负责。
    gnaggnoyil
        18
    gnaggnoyil  
       2017-12-11 01:17:26 +08:00
    对于 LZ 这种声称"只有 C 相关经验"的人来说 call/cc 真是一种降维打击.API 不同步有什么难理解的?凭什么所有语言的运行模型都必须像 C 那样只能沿着子程序调用链走.更何况 LZ 连 C 都没搞明白."函数调用运行时创建,离开后销毁".麻烦 LZ 能不能先解释解释"函数调用的创建和销毁"是怎么一回事.
    Juggernaut
        19
    Juggernaut  
    OP
       2017-12-11 10:36:58 +08:00
    @gnaggnoyil 这个……我不是来说 nodejs 不好的,学习了 nodejs 几天,一些思路与想法与大伙交流而已;至于函数创建和销毁的问题,因为只有 C 经历,我的理解是就是函数相关堆栈的申请释放,C 中的函数是执行过程的集合;不知道你所说的 nodejs 中的函数创建 /销毁是什么概念
    Juggernaut
        20
    Juggernaut  
    OP
       2017-12-11 10:42:44 +08:00
    @gnaggnoyil 大佬息怒,wwqgtxx 同学给我解释了 nodejs 的函数创建与释放了~
    Juggernaut
        21
    Juggernaut  
    OP
       2017-12-11 10:52:38 +08:00
    @wwqgtxx C 函数因为是编译期间就确定好的,执行的过程中也就涉及到堆栈的申请 /销毁; JS 可以在运行的过程中动态的创建 /销毁函数,得益于 NODEJS 所有函数属于同一个对象,对吧?貌似理由不是很充分。。。
    多谢
    Juggernaut
        22
    Juggernaut  
    OP
       2017-12-11 11:03:47 +08:00
    @cctv1005s927 大概明白了非阻塞 API 的概念了,你说的 native api 其实就是 nodejs 提供的一些底层的 api,非阻塞其实就是调用不阻塞,执行是否阻塞(是否同步返回执行结果)要看具体功能了,这样理解对吧?

    一个新问题,如果一个 http 请求触发一个非阻塞的耗时的 api 调用,在 http 请求超时之前都没能完成该原生 api 的执行,等到其执行完成后,回调函数被调用执行,但是 HTTP 请求已经超时,这中非阻塞还有意义吗?就是在阻塞的时间未知的情况下,要在规定的时间段内完成任务,这种矛盾如何解决~是我等菜鸟想的太多吗?

    感谢
    wwqgtxx
        23
    wwqgtxx  
       2017-12-11 11:27:33 +08:00 via iPhone
    @Juggernaut 你可以把 js 中的每个函数都理解成 c++中的一个类的实例,每一个 function 都是运行时 new 出来的
    至于你说的超时问题,所有异步 api 一般都会提供 timeout 设置,超时的时候会调用特殊的超时回调函数或者给普通回调函数传一个错误信息标识,另外异步操作也是可以被打断的呀,你在主线程设置一个定时器,超时了直接中断那个异步操作不就得了
    Juggernaut
        24
    Juggernaut  
    OP
       2017-12-11 11:38:38 +08:00
    @wwqgtxx 感谢,在 NODEJS 架构中,如果 JS 调用阻塞的 native api,譬如文件读写,是不是常规做法是启动新的线程来做文件读写的工作?
    wwqgtxx
        25
    wwqgtxx  
       2017-12-11 11:44:10 +08:00 via iPhone
    @Juggernaut 在写 node 的时候,这不是你该考虑的问题,就比如你写 c 的时候不需要考虑 fwrite 是如何调用系统内核的 sys_write 函数,内核又是怎么寻道然后把数据通过 dma 发给硬盘,硬盘又是怎么写入到磁粉上的

    node 的世界中最大特点是不提供任何阻塞 api,记住 node 永远是单线程的,至于它底层是怎么实现的,不是你该关心的
    sensui7
        26
    sensui7  
       2017-12-11 19:43:15 +08:00
    还以为 node 有什么新特性了呢? 现在讨论这个? 大清亡了?
    Juggernaut
        27
    Juggernaut  
    OP
       2017-12-12 14:42:12 +08:00
    @sensui7 不好意思惊扰大神,菜鸟在学习中
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2818 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 13:13 · PVG 21:13 · LAX 06:13 · JFK 09:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.