【问题标题】:reinventing the wheels: Node.JS/Event-driven programming v.s. Functional Programming?重新发明轮子:Node.JS/事件驱动编程 vs.函数式编程?
【发布时间】:2009-12-07 21:01:35
【问题描述】:

现在有关于Node.JS 的所有宣传,这是一个使用 Javascript 回调的事件驱动框架。以我有限的理解,它的主要优点似乎是你不必按顺序一步一步等待(例如,你可以获取 SQL 结果,同时调用其他功能)。

所以我的问题是:这与 CL、Haskell、Clojure 等函数式语言有何不同或更好?如果不是更好,那为什么人们不干脆做函数式语言(而不是用 Javascript 重新发明轮子)?

请注意,我在 Node.JS 和函数式编程方面都没有经验。所以一些基本的解释可能会有所帮助。

【问题讨论】:

    标签: javascript ajax haskell functional-programming


    【解决方案1】:

    阅读过 Node.JS 文档(以及不错的 slide deck)后,我认为这里的其他答案没有抓住重点:Node.JS 是基于这样的想法,即我们所期望的编写程序的风格他们阻止 I/O 是错误的,相反我们应该启动 I/O(例如读取数据库或读取套接字)并传递一个函数来处理 I/O 的结果以及请求。

    所以不要这样做:

    var result = db.query("select.."); // blocking
    // use result
    

    Node.JS 就是基于这样的思路:

    db.query("select..", function (result) {
        // use result
    });
    

    作者(Node.JS)指出,这种编程方式在许多系统中非常笨拙,因为这些语言没有闭包或匿名函数,而且库主要阻塞 I/O。然而,Javascript 提供了前者(鉴于 JS 在浏览器中以类似事件的方式使用,程序员已经习惯了它),而 Node.JS 填补了后者:作为一个完全事件驱动的 I/O 库,没有阻塞调用完全没有。

    这与函数式编程有何关系?所有函数式编程语言都提供了足够强大的闭包结构来完成 Node.JS 试图用 Javascript 完成的工作。大多数使编码变得更加容易,因为传递闭包通常是该语言的基础。

    对于 Haskell,使用 Monads,这种东西可以很容易构建。例如:

    doQuery :: DBConnection -> IO ()
    doQuery db = do
        rows <- query db "select..."
        doSomething rows
        doSomethingElse rows
    

    这些非常连续、命令式的代码行实际上是在IO monad 控制下的一系列闭包。就像你用 JavaScript 写的一样:

    db.query("select...", function (rows) {
        doSomething(rows, function () {
            doSomethingElse(rows, function () { /* done */ })
        })
    })
    

    本质上,当用函数式语言编写一元代码时,您已经按照 Node.JS 作者希望我们编写的形式编写它:顺序计算的每一步都作为闭包传递给前一个。但是,看看这段代码在 Haskell 中的表现要好得多!

    此外,您可以轻松地使用并发 Haskell 功能来轻松实现这种非阻塞操作:

    forkQuery :: DBConnection -> IO ThreadId
    forkQuery db = forkIO $ do
        rows <- query db "select..."
        doSomething rows
        doSomethingElse rows
    

    不要将 forkIO 与您习惯的昂贵的进程分叉甚至操作系统进程线程混淆。它基本上与 Node.JS 使用的轻量级执行线程相同(仅具有更丰富的语义)。就像 Node.JS 的目标一样,您可以拥有 1,000 个。

    所以,简而言之 - 我认为 Node.JS 建立在 JavaScript 中存在的工具之上,但在函数式语言中更自然。此外,我认为 Node.JS 中的所有元素都已经存在于 Haskell 及其包中,还有一些。对我来说,我只会使用 Haskell!

    【讨论】:

    • 首先+1。这是一个清晰而平衡的答案。然而,在使用了这两种方法后,我发现通过严格命名回调,一些尴尬就消失了。 JS 是一种披着 C 家族语言外衣的函数式语言,你最终会得到两者兼而有之的东西。我发现哲学上的灵活性使得使用 Node 编写 JS 代码变得更快、更有趣。不过那只是我!
    【解决方案2】:

    我也不太了解 Node.JS,但我并没有看到它(根据您的描述)与函数式编程之间有任何惊人的相似之处。根据您的描述,Node.JS 似乎旨在帮助异步编程——正如您所说“您不必按顺序逐步等待”,您可以像一个长时间运行的任务一样执行其他任务。

    函数式编程与此完全正交——即它实际上与异步性没有任何联系。你可以有一个没有另一个,或者两者都在一起,或者两者都没有。函数式编程旨在消除程序中的副作用,并允许函数作为语言的一等成员,以类似于其他值的方式进行操作和组合。

    【讨论】:

    • 好吧,老实说,函数式编程并不意味着纯语言。 Haskell 只是选择这样做。
    • 请注意,我从未声称它确实如此。编程风格本身就是我定义的。对此争议不大。关于应该允许将什么称为“函数式编程语言”——任何允许这种风格的语言,任何主要关注支持该风格的语言,或者只支持不支持其他风格的语言,一直存在争论。这是一场不同的辩论。
    【解决方案3】:

    这并不是真正的“重新发明轮子”。 Javascript 本身并不是真正的函数式语言,但它基于 Lisp,而这正是它的设计初衷。在我看来,Javascript 作为一种 Lisp 式的函数式语言确实比它作为一种 OO 语言更强大。这就是为什么像 jQuery 这样具有强大功能* 设计的框架非常适合该语言的原因。

    (* 注意:显然不是纯粹的,但功能与 Scheme 大致相同。)

    【讨论】:

      【解决方案4】:

      我还没有使用过 node.js,但我肯定对它很感兴趣,很快就会尝试一下。这里已经有很多关于函数式编程等的很好的答案,所以我不会深入讨论。

      你问为什么不在服务器上使用一些其他的语言,比如haskell、Closure等。对我来说,node.js相对于其他语言的吸引力在于它是javascript。我的应用程序在客户端的 javascript 中已经很重了,所以这意味着我可以在服务器和客户端上使用一种语言。

      我希望这将简化和简化开发,因为我不需要如此剧烈地切换上下文。如果可以共享客户端和服务器上使用的某些逻辑(可能是表单验证代码等),甚至可能会减少工作量。

      【讨论】:

        【解决方案5】:

        Javascript 在节点中作为网络服务器的关键作用在于它主要是事件驱动的。

        我相信函数式编程在并发方面具有优势,这要归功于其他方面的不变性。

        不确定其他函数式语言是如何事件驱动的,只是想强调一下它作为节点优势的一部分。

        【讨论】:

          【解决方案6】:

          客户端和服务器之间的差距缩小的主要好处之一是能够在客户端和服务器上重用代码。例如,如果您想为现代浏览器提供丰富且动态的 AJAX 网站,并为旧浏览器提供精简版本,您可以使用相同的显示代码来格式化客户端和服务器上的传入数据。

          与此相关的其他好处包括 HTML5/Google Gears/Adobe Air 能够拥有本地存储数据库和服务器以离线运行 Web 应用程序,您可以将传统上在服务器上的代码存储在本地,以备不时之需可用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-23
            • 2010-09-19
            • 2015-10-06
            • 1970-01-01
            • 1970-01-01
            • 2014-12-29
            • 1970-01-01
            • 2011-06-26
            相关资源
            最近更新 更多