mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Avoid infinite digest loop caused by $watch and $timeout (#10122)
Backports PR #10036
**Commit 1:**
Avoid infinite digest loop in debounce
The custom debounce implementation uses Angular's `$timeout`, which
interacts unfavourably with the unconditional `$watch` handler used in
the `fixed-scroll` directive. It results in an infinite digest being
triggered about every 100ms. To avoid that, this commit uses the
`invokeApply` option of `$timeout` and instead calls `$scope.$apply`
conditionally.
* Original sha: 13c677d613
* Authored by Felix Stürmer <stuermer@weltenwort.de> on 2017-01-24T11:30:41Z
This commit is contained in:
parent
d2af8a157e
commit
e0827ef614
3 changed files with 16 additions and 12 deletions
|
@ -13,7 +13,8 @@ module.service('debounce', ['$timeout', function ($timeout) {
|
|||
let result;
|
||||
options = _.defaults(options || {}, {
|
||||
leading: false,
|
||||
trailing: true
|
||||
trailing: true,
|
||||
invokeApply: true,
|
||||
});
|
||||
|
||||
function debounce() {
|
||||
|
@ -32,7 +33,7 @@ module.service('debounce', ['$timeout', function ($timeout) {
|
|||
if (timeout) {
|
||||
$timeout.cancel(timeout);
|
||||
}
|
||||
timeout = $timeout(later, wait);
|
||||
timeout = $timeout(later, wait, options.invokeApply);
|
||||
|
||||
if (callNow) {
|
||||
result = func.apply(self, args);
|
||||
|
|
|
@ -9,15 +9,16 @@ import Promise from 'bluebird';
|
|||
describe('FixedScroll directive', function () {
|
||||
|
||||
let compile;
|
||||
let flushPendingTasks;
|
||||
let trash = [];
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.module(function ($provide) {
|
||||
$provide.service('debounce', () => {
|
||||
return targetFunction => targetFunction;
|
||||
});
|
||||
}));
|
||||
beforeEach(ngMock.inject(function ($compile, $rootScope) {
|
||||
beforeEach(ngMock.inject(function ($compile, $rootScope, $timeout) {
|
||||
|
||||
flushPendingTasks = function flushPendingTasks() {
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
};
|
||||
|
||||
compile = function (ratioY, ratioX) {
|
||||
if (ratioX == null) ratioX = ratioY;
|
||||
|
@ -46,7 +47,7 @@ describe('FixedScroll directive', function () {
|
|||
}).appendTo($el);
|
||||
|
||||
$compile($parent)($rootScope);
|
||||
$rootScope.$digest();
|
||||
flushPendingTasks();
|
||||
|
||||
return {
|
||||
$container: $el,
|
||||
|
@ -97,7 +98,7 @@ describe('FixedScroll directive', function () {
|
|||
|
||||
expect(off.callCount).to.be(0);
|
||||
els.$container.width(els.$container.prop('scrollWidth'));
|
||||
els.$container.scope().$digest();
|
||||
flushPendingTasks();
|
||||
expect(off.callCount).to.be(2);
|
||||
checkThisVals('$.fn.off', off);
|
||||
|
||||
|
|
|
@ -110,14 +110,16 @@ uiModules
|
|||
const newWidth = $el.width();
|
||||
|
||||
if (scrollWidth !== newScrollWidth || width !== newWidth) {
|
||||
setup();
|
||||
$scope.$apply(setup);
|
||||
|
||||
scrollWidth = newScrollWidth;
|
||||
width = newWidth;
|
||||
}
|
||||
}
|
||||
|
||||
const debouncedCheckWidth = debounce(checkWidth, 100);
|
||||
const debouncedCheckWidth = debounce(checkWidth, 100, {
|
||||
invokeApply: false,
|
||||
});
|
||||
$scope.$watch(debouncedCheckWidth);
|
||||
|
||||
// cleanup when the scope is destroyed
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue