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的更多相关文章

  1. Angular Multiple HTTP Requests with RxJS

    原文:https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs ----------------------------- ...

  2. [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 ...

  3. [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 ...

  4. [AngularJS 2 实践 一]My First Angular App

    最近一直在看关于AngularJS 2的资料,查看了网上和官网很多资料,接下来就根据官网教程步骤一步步搭建我的第一个Angular App AngularJS 2说明请参考:http://cnodej ...

  5. [RxJS] Refactoring Composable Streams in RxJS, switchMap()

    Refactoring streams in RxJS is mostly moving pieces of smaller streams around. This lessons demonstr ...

  6. [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 ...

  7. AngularJS进阶(二十五)requirejs + angular + angular-route 浅谈HTML5单页面架构

    requirejs + angular + angular-route 浅谈HTML5单页面架构 众所周知,现在移动Webapp越来越多,例如天猫.京东.国美这些都是很好的例子.而在Webapp中,又 ...

  8. angularjs探秘<三> 控制器controller及angular项目结构

    先来看一个例子 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&quo ...

  9. AngularJS源码解析1:angular自启动过程

    angularJS加载进来后,会有一个立即执行函数调用,在源代码的最下面是angular初始化的地方.代码展示: bindJQuery(); publishExternalAPI(angular); ...

随机推荐

  1. Linux Curses编程实现贪吃蛇

    curses库 简单而言,提供UNIX中多种终端 操作光标和显示字符 的接口.我们常见的vi就是使用curses实现的.现在一般都用ncurses库. Linux下curses函数库    Linux ...

  2. CodeChef CBAL

    题面: https://www.codechef.com/problems/CBAL 题解: 可以发现,我们关心的仅仅是每个字符出现次数的奇偶性,而且字符集大小仅有 26, 所以我们状态压缩,记 a[ ...

  3. VS2013相关资料

    visual studio 主页 http://msdn.microsoft.com/en-us/vstudio/aa718325.aspx vs2013 download http://www.mi ...

  4. 大话设计模式之策略模式(strategy)

    策略模式:它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响使用算法的用户. 针对商城收银模式,打折,返现促销等的例子: 打折还是促销其实都是一些算法,可以用工厂模式来 ...

  5. LightOj_1342 Aladdin and the Magical Sticks

    题目链接 题意: 地上有n种棍子, 其中有两种类型, 一种类型是可识别, 一种类型是不可识别, 每个棍子都有一个权值. 当你捡到可识别的, 那么你以后就不会再捡这个棍子, 如果是不可识别的, 那么你有 ...

  6. ARCI--做事情的重要方法论

    很多朋友都可能碰到这样的情况,有一个任务曾经开会讨论过,目标,时间,参与人都有提到,但是最终就是不了了之,没有下文了,而且后面想起来,要追究责任的时候,发现似乎都没有责任,无从追究.如果这种情况出现, ...

  7. Hdu5517 Triple

    Description Given the finite multi-set \(A\) of \(n\) pairs of integers, an another finite multi-set ...

  8. Astyle:代码格式化工具简明指南

    astyle是一个我自己常用的开放源码工具.它可以方便的将程序代码格式化成自己想要的样式而不必人工修改.本来嘛,作为高等生物应该优先去做一些智慧的事情,而不是把时间消耗在机器可以完美完成的事情上. 想 ...

  9. 关于android布局的两个属性dither和tileMode

    首先,两个单词的中文意思分别是dither(抖动)和tileMode(平铺) 1,先来介绍tileMode(平铺) 它的效果类似于 让背景小图不是拉伸而是多个重复(类似于将一张小图设置电脑桌面时的效果 ...

  10. Android WebView JavaScript交互

    今天介绍一下,Android中Webview与JavaScript的交互,首先是在布局文件里添加webview控件: <WebView android:id="@+id/webview ...