From 514034d329262228f5eb79866f6429397fbd4e8d Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Thu, 28 May 2020 11:03:33 +0100 Subject: [PATCH] Fixed and improved members stats "debounced" fetches no issue - the "days changed" logic was incorrect so we were always performing new fetches rather than using existing data - added a minor improvement that returns an in-progress fetch promise if we have one and params haven't changed - avoids triggering unnecessary extra fetches in the rare occasions the chart is re-rendered before a previous stats fetch has finished --- ghost/admin/app/services/members-stats.js | 34 +++++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/ghost/admin/app/services/members-stats.js b/ghost/admin/app/services/members-stats.js index be1d1481ab..bf524f783f 100644 --- a/ghost/admin/app/services/members-stats.js +++ b/ghost/admin/app/services/members-stats.js @@ -1,5 +1,6 @@ import Service from '@ember/service'; import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency-decorators'; import {tracked} from '@glimmer/tracking'; export default class MembersStatsService extends Service { @@ -9,26 +10,35 @@ export default class MembersStatsService extends Service { @tracked stats = null; fetch({days}) { - // return existing stats unless data is > 1 min old - let daysChanged = days === this._days; + let daysChanged = days !== this._days; let staleData = this._lastFetched && this._lastFetched - new Date() > 1 * 60 * 1000; + + // return an already in-progress promise unless params have changed + if (this._fetchTask.isRunning && !this._forceRefresh && !daysChanged) { + return this._fetchTask.last; + } + + // return existing stats unless data is > 1 min old if (this.stats && !this._forceRefresh && !daysChanged && !staleData) { return Promise.resolve(this.stats); } - this._forceRefresh = false; - this._days = days; - this._lastFetched = new Date(); - - let statsUrl = this.ghostPaths.url.api('members/stats'); - - return this.ajax.request(statsUrl, {data: {days}}).then((stats) => { - this.stats = stats; - return stats; - }); + return this._fetchTask.perform(...arguments); } invalidate() { this._forceRefresh = true; } + + @task + *_fetchTask({days}) { + this._days = days; + this._lastFetched = new Date(); + this._forceRefresh = false; + + let statsUrl = this.ghostPaths.url.api('members/stats'); + let stats = yield this.ajax.request(statsUrl, {data: {days}}); + this.stats = stats; + return stats; + } }