【问题标题】:Lazy event streams in JavaScriptJavaScript 中的延迟事件流
【发布时间】:2014-02-02 17:48:22
【问题描述】:

我正在尝试在 JavaScript 中模拟功能反应式编程领域的事件流。基本上有两种方法可以做到这一点:

  1. 为每个事件流提供一个listeners 数组,并允许外部代码订阅流中的事件。我不喜欢这个解决方案,因为它需要大量的簿记和可变状态。
  2. 在 JavaScript 中实现惰性求值和 thunk 以模拟惰性列表,允许您将事件流显示为由常规事件侦听器生成的惰性事件列表。不记账。

显然第二种方法更可取。因此,我刻苦地编写了一些组合子来在 JavaScript 中启用惰性求值:

function lazy(f, a) {
    return function (k) {
        return k(apply(f, a));
    };
}

function apply(f, a) {
    return f.apply(null, a);
}

lazy 组合器接受一个函数和一个参数列表,并返回一个代表函数调用返回值的 thunk。

function eval(a) {
    return typeof a === "function" ? a(id) : a;
}

function id(a) {
    return a;
}

eval 组合器要么接受一个 thunk,评估它并返回它的值,要么返回一个不变的急切值。它允许您对惰性值和渴望值一视同仁。

接下来我写了一个cons函数来创建一个列表:

function cons(head, tail) {
    return {
        head: head,
        tail: tail
    };
}

然后我写了一些实用函数来测试惰性求值:

function fib(a, b) {
    var c = a + b;
    return cons(c, lazy(fib, [b, c]));
}

function take(n, xs) {
    return xs && n > 0 ?
        cons(xs.head, lazy(take, [n - 1, eval(xs.tail)])) :
    null;
}

function toArray(xs) {
    return xs ?
        [xs.head].concat(toArray(eval(xs.tail))) :
    [];
}

最后我懒惰地得到了前10个斐波那契数如下:

var xs = take(10, fib(-1, 1));

alert(JSON.stringify(toArray(xs))); // [0,1,1,2,3,5,8,13,21,34]

它就像一个魅力:http://jsfiddle.net/Kc5P2/

所以现在我尝试使用惰性列表在 JavaScript 中创建事件流构造函数。然而,由于事件是异步生成的,我推测我需要将所有函数转换为延续传递样式。

问题的关键在于,如果 thunk 的值尚不可用,则无法推迟对 thunk 的评估。解决方法是创建一个异步的eval函数如下:

function asyncEval(a, k) {
    typeof a === "function" ? a(k) : k(a);
}

现在您可以从事件流构造函数返回一个异步 thunk,如下所示:

function getEventStream(type, target) {
    return function (k) {
        target.addEventListener(type, function listener(event) {
            target.removeEventListener(type, listener);
            k(cons(event, getEventStream(type, target)));
        });
    };
}

不幸的是,现在我们已经使它异步了,我们还需要为所有在惰性列表上运行的函数创建异步版本(例如take)。我们现在不仅陷入了回调地狱,而且我们还需要每个函数的两个版本:同步和异步。

你会如何解决这个问题?有没有其他方法可以在 JavaScript 中创建惰性事件流?顺便说一句,我已经使用订阅模型为 JavaScript 中的事件流创建了一个要点:https://gist.github.com/aaditmshah/8381875

【问题讨论】:

    标签: javascript functional-programming lazy-evaluation reactive-programming


    【解决方案1】:

    我会选择 Promise,它非常适合表示同步和异步可用的值。

    然后,流将是包含头部的结构的承诺,以及包含尾部的承诺。您可能想在https://stackoverflow.com/a/17414193/1048572 上查看我的演示实现。

    【讨论】:

      【解决方案2】:

      去年我对 JavaScript 中的流进行了一些研究:

      What's the relationship between streamjs and linqjs

      我最终对 streamjs 进行了逆向工程,并为我的目的对其进行了扩展。

      【讨论】:

        猜你喜欢
        • 2012-07-23
        • 2010-11-18
        • 2020-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-05
        • 1970-01-01
        相关资源
        最近更新 更多