[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); ...
随机推荐
- ext 金额大写
//数字转换成大写金额函数 function atoc(numberValue) { numberValue = numberValue.replace(/,/g,''); numberValue = ...
- android调试bug集锦 onActivityResult立即返回,并且被CANCEL
症状: 在使用startActivityForResult调用照相机或者选择图片的时候,总是onActivityResult立马返回,resultCode=0 CANCEL. startActivit ...
- linux源码“.config”文件分析
一..config文件概述 .config文件是linux内核配置文件,当执行#make uImage编译生成内核时,顶层的Makefile会读取.config文件的内容,根据这个配置文件来编译所定制 ...
- golang开发android环境搭建_window
golang开发android环境搭建介绍 一 安装依赖软件: git:版本管理 go: go开发环境(版本>=1.5),可直接下载window版的go安装包. android studio: ...
- python 大文件以行为单位读取方式比对
http://www.cnblogs.com/aicro/p/3371986.html 先前需要做一个使用python读取大文件(大于1G),并逐条存入内存进行处理的工作.做了很多的尝试,最终看到了如 ...
- JS仿淘宝详情页菜单条智能定位效果
类似于淘宝详情页菜单条智能定位 对于每个人来说并不陌生!如下截图所示:红色框的那部分! 基本原理: 是用JS侦听滚动事件,当页面的滚动距离(页面滚动的高度)大于或者等于 "对象"( ...
- Android中moveTo、lineTo、quadTo、cubicTo、arcTo详解(实例)
1.Why 最近在写android画图经常用到这几个什么什么To,一开始还真不知道cubicTo这个方法,更不用说能不能分清楚它们了,所以特此来做个小笔记,记录下moveTo.lineTo.quadT ...
- BZOJ2375: 疯狂的涂色
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2375 小t非常喜爱画画,但是他还是一个初学者.他最近费尽千辛万苦才拜到已仙逝的达 芬奇为师(神 ...
- Linux Shell编程(19)——测试与分支
case和select结构在技术上说不是循环,因为它们并不对可执行的代码块进行迭代.但是和循环相似的是,它们也依靠在代码块的顶部或底部的条件判断来决定程序的分支.在代码块中控制程序分支case (in ...
- 1047 - Neighbor House(简单线性DP)
题目大意: 给你n个房子,要求把房子染成R,G,B三种的一种颜色, 要求相邻的颜色不能一样. dp[第i个房子][第j种颜色] 转移一下就行了. #include<cstdio&g ...