使用 transducers-js 和 most.js 创建从 Json 到流的管道
Create a pipeline from Json to streams with transducers-js and most.js
我有这个Amd module
define(function (require, exports, module) {
'use strict';
var t = require("transducers");
var most = require("most");
var groupby = function (prev, curr) {
var key = curr.type;
if (!prev[key]) {
prev[key] = [curr];
} else {
prev[key].push(curr);
}
return prev;
};
function category(kv) {
return {
type: kv[0],
label: kv[1][0].label,
counter: kv[1].length
}
}
function dom(cat) {
var el = document.createElement("li");
el.innerHTML = cat.label;
return el;
}
function append(prev, curr) {
prev.appendChild(curr);
return prev;
}
function createClick(prev, curr) {
return prev.merge(most.fromEvent("click", curr)
.map(function (e) {
return e.currentTarget.innerHTML;
})
)
}
var xf = t.comp(
t.map(category),
t.map(dom)
);
module.exports = {
main: function (data) {
var groups = t.reduce(groupby, {}, data);
var container = t.transduce(xf, append, document.querySelector("ul"), groups);
var streams = t.reduce(createClick, most.empty(), [].slice.call(container.querySelectorAll("li"), 0));
streams.forEach(function (e) {
console.log("click", e);
});
}
};
});
Main 函数获取项目列表,然后按 'type' 属性 对它们进行分组。之后它创建并附加 < li > 元素。最后,它创建了点击流。我是反应式编程和传感器方面的新手。
但我想知道是否有创建管道的方法。
我很麻烦,因为 groupby 是一个缩减,不能在转换器中组合它。我确定我错过了什么。谢谢
尝试将您的问题分成可以对单个项目和集合进行操作的问题,并等到最后一个再减少它们。还要检查经常错过的 "scan" 操作,这可以避免过度激进的减少
在您的示例中,列出了 3 个可能的减少操作:
- 将所有点击流合并为一个事件流
- 将所有 dom 合并为一个 ul
- 计数
这些都可以通过扫描来完成,但问题是你想要唯一的类别,但你也计算了非唯一的类别。从你的例子中不清楚这是否真的是一个要求......
由于大多数已经可以像换能器一样工作,所以您实际上并不需要它们。对于这个例子,我将坚持使用纯 mostjs;
var most = require("most");
function gel(tag) {
return document.createElement(tag);
}
var cache = Object.create(null);
function main(dataArray) {
most.from(dataArray)
//only pass along unique items to represent categories
//optionally, also count...
.filter(function uniq(item) {
var category = item.type;
if (!(category in cache))
cache[category] = 0;
cache[category]++;
return cache[category] == 1;
})
//transform
.map(function makeLI(item) {
var li = gel("li");
li.innerHTML = item.label;
item.dom = li;
})
//attach click handler
.map(function (item) {
item.click = most
.fromEvent("click", item.dom)
.map(function(e) {
item.label;
});
return item;
})
// merge
.scan(function mergeIn(all, item) {
el.appendChild(item.dom);
clicks.merge(item.click);
}, { ul: gel("ul"), clicks: most.empty() })
//force stream init b creating a demand
.drain()
//most resolve stream into promises, but we could have just
//as easily used reduce here instead
.then(function onComplete(all) {
all.clicks.forEach(function(msg) {
console.log("click", e);
})
})
}
可能会有更多变化。例如,如果我们想为每个类别项目添加一个子列表,我们可以将一个流附加到每个类别的上下文对象,并逐步附加到每个子项
我有这个Amd module
define(function (require, exports, module) {
'use strict';
var t = require("transducers");
var most = require("most");
var groupby = function (prev, curr) {
var key = curr.type;
if (!prev[key]) {
prev[key] = [curr];
} else {
prev[key].push(curr);
}
return prev;
};
function category(kv) {
return {
type: kv[0],
label: kv[1][0].label,
counter: kv[1].length
}
}
function dom(cat) {
var el = document.createElement("li");
el.innerHTML = cat.label;
return el;
}
function append(prev, curr) {
prev.appendChild(curr);
return prev;
}
function createClick(prev, curr) {
return prev.merge(most.fromEvent("click", curr)
.map(function (e) {
return e.currentTarget.innerHTML;
})
)
}
var xf = t.comp(
t.map(category),
t.map(dom)
);
module.exports = {
main: function (data) {
var groups = t.reduce(groupby, {}, data);
var container = t.transduce(xf, append, document.querySelector("ul"), groups);
var streams = t.reduce(createClick, most.empty(), [].slice.call(container.querySelectorAll("li"), 0));
streams.forEach(function (e) {
console.log("click", e);
});
}
};
});
Main 函数获取项目列表,然后按 'type' 属性 对它们进行分组。之后它创建并附加 < li > 元素。最后,它创建了点击流。我是反应式编程和传感器方面的新手。
但我想知道是否有创建管道的方法。
我很麻烦,因为 groupby 是一个缩减,不能在转换器中组合它。我确定我错过了什么。谢谢
尝试将您的问题分成可以对单个项目和集合进行操作的问题,并等到最后一个再减少它们。还要检查经常错过的 "scan" 操作,这可以避免过度激进的减少
在您的示例中,列出了 3 个可能的减少操作: - 将所有点击流合并为一个事件流 - 将所有 dom 合并为一个 ul - 计数
这些都可以通过扫描来完成,但问题是你想要唯一的类别,但你也计算了非唯一的类别。从你的例子中不清楚这是否真的是一个要求......
由于大多数已经可以像换能器一样工作,所以您实际上并不需要它们。对于这个例子,我将坚持使用纯 mostjs;
var most = require("most");
function gel(tag) {
return document.createElement(tag);
}
var cache = Object.create(null);
function main(dataArray) {
most.from(dataArray)
//only pass along unique items to represent categories
//optionally, also count...
.filter(function uniq(item) {
var category = item.type;
if (!(category in cache))
cache[category] = 0;
cache[category]++;
return cache[category] == 1;
})
//transform
.map(function makeLI(item) {
var li = gel("li");
li.innerHTML = item.label;
item.dom = li;
})
//attach click handler
.map(function (item) {
item.click = most
.fromEvent("click", item.dom)
.map(function(e) {
item.label;
});
return item;
})
// merge
.scan(function mergeIn(all, item) {
el.appendChild(item.dom);
clicks.merge(item.click);
}, { ul: gel("ul"), clicks: most.empty() })
//force stream init b creating a demand
.drain()
//most resolve stream into promises, but we could have just
//as easily used reduce here instead
.then(function onComplete(all) {
all.clicks.forEach(function(msg) {
console.log("click", e);
})
})
}
可能会有更多变化。例如,如果我们想为每个类别项目添加一个子列表,我们可以将一个流附加到每个类别的上下文对象,并逐步附加到每个子项