我必须合并流以获取加载图像的URL:一个用于放置事件的流和一个用于文件输入更改的流.在每个新路径上,我加载此图像并将其绘制到画布上.此画布将传递到另一个流中.它看起来像这样:
// prevent browsers default behavior for dropTargetElement
[ 'drop', 'dragover' ].forEach(function(eventName) {
Rx.Observable.fromEvent(dropTargetElement, eventName).subscribe(function(event) {
event.preventDefault();
});
});
// file path stream merged from openFileInputs change and openFileDropTargets drop
Rx.Observable.merge(Rx.Observable.fromEvent(inputElement, 'change').map(function(event) {
return event.target.value;
}), Rx.Observable.fromEvent(dropTargetElement, 'drop').map(function(event) {
return event.dataTransfer.files[0].path;
})).map(function(path) {
var image = new Image();
image.src = path;
// note: I return an Observable in this map function
// is this even good practice? if yes, is mergeAll the best
// way to get the "load" event?
return Rx.Observable.fromEvent(image, 'load');
}).mergeAll().map(function(event) {
return event.path[0];
}).subscribe(function(image) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
canvasState.onNext(canvas);
});
Run Code Online (Sandbox Code Playgroud)
(附带问题:是否"允许"返回Observables map?)
我canvasState看起来像这样:
var canvasState = new Rx.BehaviorSubject(undefined);
// draw image
canvasState.filter(function(canvas) {
return !!canvas;
}).subscribe(function drawImage(canvas) {
document.body.appendChild(canvas);
});
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,如果我的画布值非常真实,我会将画布附加到主体上.但是每当有新画布进来时我都想删除旧画布.实现这一目标的最佳方法是什么?这样的事情可能吗?
// draw image
canvasState.filter(function(canvas) {
return !!canvas;
}).beforeNext(function(oldCanvas) {
// remove old one
}).subscribe(function drawImage(canvas) {
document.body.appendChild(canvas);
});
Run Code Online (Sandbox Code Playgroud)
是的,让一个map操作返回一个Observable 是正常的.这为您提供了一个可观察的可观察流流.有Rx 3操作来展平嵌套的可观察的一个级别:
maxConcurrent参数来限制并发内部订阅的数量.当达到限制时,新的内部observable会排队,并且在前一个内部observable完成之前不会被订阅.Merge将maxConcurrent设置为1.switch时,你只想要听最新的内流.(在我的代码中,我还实现了第四个展平运算符:concatLatest就像concat,但是当内部流完成时,它不会跳转到队列中的下一个流,而是直接跳转到队列中的最新序列,抛出消除任何内流.它介于两者之间concat和switch行为中,我觉得它在处理背压时非常有用,同时仍能产生结果).
所以,拥有.map(...).mergeAll()或者.map(...).concatAll()或者是非常普遍的.map(...).switch().它是如此常见,这三种情况有Rx方法:
source.flatMap(selector) 相当于 source.map(selector).mergeAll()source.concatMap(selector) 相当于 source.map(selector).concatAll()source.flatMapLatest(selector) 相当于 source.map(selector).switch()有了上述信息,我建议您使用switch而不是merge.正如您的代码现在所处,如果有人快速更改了值,您可以同时输出2个图像请求,如果它们以错误的顺序完成,您将最终得到错误的最终画布. switch将取消陈旧的图像请求并切换到新的图像请求.
请注意,如果用户继续更快地更改值,而不是图像请求可以完成,那么他们将永远看不到任何图像,因为您将继续切换到新图像.这是我通常使用我的地方,concatLatest因为它会不时地完成一些中间请求,同时它正在努力跟上.因人而异.
当我的可观察流有一个映射操作产生必须清理的资源时,我倾向于使用,scan因为它可以跟踪我之前的值(我不需要设置一个闭包变量来保存前一个值):
canvasState
.filter(function (c) { return !!c; })
.scan({}, function (acc, canvas) {
return { previous: acc.canvas, canvas: canvas };
})
.subscribe(function (v) {
// remove the old canvas
if (v.previous) { document.body.removeChild(v.previous); }
// add the new one
document.body.appendChild(v.canvas);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2488 次 |
| 最近记录: |