[RxJS + AngularJS] Sync Requests with RxJS and Angular
When you implement a search bar, the user can make several different queries in a row. With a Promise based implementation, the displayed result would be what the longest promise returns. This is the problem which we want to solve.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.rawgit.com/lodash/lodash/3.0.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/1.3.3/less.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.3.22/rx.all.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-app="APP">
<div>
<p>Click on "Pets" then on "Nothing" in each form</p>
<p>Because pets' promise take long to resolve (longer than nothing's), it ends up with inconsistent output in Basic setup: nothing should be displayed but pets arrive!</p>
<p>RxJs is an elegant way to prevent this concurrency problems from appearing.</p>
</div>
<div ng-controller="StandardController as standard" style="margin-top:50px;">
<p>Basic setup</p>
<input id="s-pets" name="standardEntityType" type="radio" ng-model="standard.filters.entityType" value="pets">
<label for="s-pets">Pets</label> <input id="s-colors" name="standardEntityType" type="radio" ng-model="standard.filters.entityType" value="colors">
<label for="s-colors">Colors</label> <input id="s-nothing" name="standardEntityType" type="radio" ng-model="standard.filters.entityType" value="nothing">
<label for="s-nothing">Nothing</label> <p>
{{ standard.filters | json }}
</p>
<ul>
<li ng-repeat="entity in standard.entities">
{{ entity.name }}
</li>
</ul>
</div>
</body>
</html>
console.clear();
angular.module('APP', [])
.service('dataService', function($q, $timeout, $rootScope){
var colors = [
{ name: 'red' },
{ name: 'blue' },
{ name: 'white' }
];
var pets = [
{ name: 'cat' },
{ name: 'dog' }
];
function fakeAjax(returnValue, delay){
return $q(function(resolve){
$timeout(function() {
resolve(returnValue);
}, delay);
});
}
function getColors(){
return fakeAjax(colors, 1500);
}
function getPets(){
return fakeAjax(pets, 3000);
}
function nullResponse(){
return fakeAjax([], 1);
}
var mapping = {
colors: getColors,
pets: getPets
};
return {
getEntities: function(type){
if (mapping[type])
return mapping[type]();
else
return nullResponse();
}
};
})
.controller('StandardController', function($scope, dataService){
this.entities = [];
this.filters = {};
var controller = this;
function searchEntities(type){
dataService.getEntities(type)
.then(function(entities){
controller.entities = entities;
});
}
$scope.$watch(function(){
return controller.filters.entityType;
}, function(newVal){
searchEntities(newVal);
});
});
Solution 1: Add lodash _.debounce method to add some delay.
.controller('StandardController', function($scope, dataService){
this.entities = [];
this.filters = {};
var controller = this;
function _searchEntities(type){
dataService.getEntities(type)
.then(function(entities){
controller.entities = entities;
});
}
var searchEntities = _.debounce(_searchEntities, 1500);
$scope.$watch(function(){
return controller.filters.entityType;
}, function(newVal){
searchEntities(newVal);
});
});
The problem here is we have to assume a correct time. Too long, and the UI is not responsible enough, and too short, and we may encounter weirdness again.
Solution 2: Using RxJS
.controller('StandardController', function($scope, dataService){
this.entities = [];
this.filters = {};
var controller = this;
var Observable = Rx.Observable;
var source = Observable.create(function(observe){
$scope.$watch(function(){
return controller.filters.entityType;
}, function(newType){
observe.onNext(newType);
});
}).flatMapLatest(function(type){
return Observable.fromPromise(dataService.getEntities(type));
});
var sub = source.subscribe(function(entities){
controller.entities = entities;
});
});
No matter what order we click the radio buttons, we'll always get the expected outcome. RxJS will handle that for us. The main benefit of RxJS over mere promises is we always get the latest query results. You can see, this implementation of Rx has a way to cancel promises.
Two methos to apply:
.controller('StandardController', function($scope, dataService){
this.entities = [];
this.filters = {};
var controller = this;
var Observable = Rx.Observable;
var source = Observable.create(function(observe){
$scope.$watch(function(){
return controller.filters.entityType;
}, function(newType){
observe.onNext(newType);
});
}).debounce(500).flatMapLatest(function(type){
return Observable.fromPromise(dataService.getEntities(type));
});
var sub = source.subscribe(function(entities){
controller.entities = entities;
});
$scope.$on('destory', function(){
sub.dispose();
});
});
The first thing is to clean after yourself. On each destroy event on the scope, so basically, whenever you use a router, it could be on route change, you have to dispose the listener so Rx knows it can get rid of everything linked to it.
The second thing is we don't want to put too much pressure on our server, so we are going to use debounce again. It's very important to understand here that debounce is not a way to avoid UI issues. It's a way to avoid useless server queries.
[RxJS + AngularJS] Sync Requests with RxJS and Angular的更多相关文章
- Angular Multiple HTTP Requests with RxJS
原文:https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs ----------------------------- ...
- [Vue-rx] Cache Remote Data Requests with RxJS and Vue.js
A Promise invokes a function which stores a value that will be passed to a callback. So when you wra ...
- [AngularJS] Consistency between ui-router states and Angular directives
ui-router's states and AngularJS directives have much in common. Let's explores the similarities bet ...
- [AngularJS 2 实践 一]My First Angular App
最近一直在看关于AngularJS 2的资料,查看了网上和官网很多资料,接下来就根据官网教程步骤一步步搭建我的第一个Angular App AngularJS 2说明请参考:http://cnodej ...
- [RxJS] Refactoring Composable Streams in RxJS, switchMap()
Refactoring streams in RxJS is mostly moving pieces of smaller streams around. This lessons demonstr ...
- [RxJS] Reactive Programming - Why choose RxJS?
RxJS is super when dealing with the dynamic value. Let's see an example which not using RxJS: var a ...
- AngularJS进阶(二十五)requirejs + angular + angular-route 浅谈HTML5单页面架构
requirejs + angular + angular-route 浅谈HTML5单页面架构 众所周知,现在移动Webapp越来越多,例如天猫.京东.国美这些都是很好的例子.而在Webapp中,又 ...
- angularjs探秘<三> 控制器controller及angular项目结构
先来看一个例子 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&quo ...
- AngularJS源码解析1:angular自启动过程
angularJS加载进来后,会有一个立即执行函数调用,在源代码的最下面是angular初始化的地方.代码展示: bindJQuery(); publishExternalAPI(angular); ...
随机推荐
- destoon代码从头到尾捋一遍
destoon® B2B网站管理系统(以下简称destoon)由西安嘉客信息科技有限责任公司独立研发并推出,对其拥有完全知识产权,中国国家版权局计算机软件著作权登记号:2009SR037570. 系统 ...
- Dalvik虚拟机进程和线程的创建过程分析
从前面Dalvik虚拟机的运行过程分析一文可以知道,Dalvik虚拟机除了可以执行Java代码之外,还可以执行Native代码,也就是C/C++函数. 这些C/C++函数在执行的过程中,又可以通过本地 ...
- UVA 10763 Foreign Exchange
Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Description Your non- ...
- show
showproperties thefrm.Controls --显示属性??showmethods thefrm.Menu---显示功能?? showclass "*bitmap*&quo ...
- 【Java】java数据库连接池配置的几种方法
今天遇到了关于数据源连接池配置的问题,发现有很多种方式可以配置,现总结如下,希望对大家有所帮助:(已Mysql数据库为例) 一,Tomcat配置数据源: 方式一:在WebRoot下面建文件夹META- ...
- PHP 7.0 安装使用与性能监测!
PHP 7.0发布,网上关于新版的介绍很多,介于 7.0 在正式发布之前已经发过若干个 Beta.8个 RC,应该不会出现重大问题.今日我将一台机器升级至 PHP 7.0 并将有关信息记录如下. 本人 ...
- gridview数据导出到word和excel以及excel的导入
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI ...
- 运行时改变控件的大小(点击后立刻ReleaseCapture,然后计算位移,最后发消息改变位置)——最有趣的是TPanel其实也有窗口标题,因此可发HTCAPTION消息
//光标在控件不同位置时的样式 // 由于拐角这点手动精确实在困难 所以用范围 范围+3 这样很容易就找到这一点了 procedure CtrlMouseMove(Ctrl: TWinControl; ...
- Java ftp断点续传
FtpTransFile类 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcept ...
- bzoj2821
其实和bzoj2724是一样的都是先处理多个块的答案,然后多余部分暴力空间要注意一下,还是O(nsqrt(n)); ..,..] of longint; g:..,..] of longint; a, ...