Skip to content

amp-bind: Rate-limit history operations#23938

Merged
dreamofabear merged 11 commits intoampproject:masterfrom
dreamofabear:bind-history-rate-limit
Aug 15, 2019
Merged

amp-bind: Rate-limit history operations#23938
dreamofabear merged 11 commits intoampproject:masterfrom
dreamofabear:bind-history-rate-limit

Conversation

@dreamofabear
Copy link
Copy Markdown

@dreamofabear dreamofabear commented Aug 14, 2019

Fixes #17969.

  • Use a queue to store history replace/push.
  • Debounce queue flushes on replace but immediately flush on push.
  • Collapse consecutive queued replaces.

@dreamofabear dreamofabear force-pushed the bind-history-rate-limit branch from f991d7d to c2a7d17 Compare August 14, 2019 00:16
@dreamofabear dreamofabear force-pushed the bind-history-rate-limit branch from 7558fed to 093abb8 Compare August 14, 2019 01:09
@dreamofabear
Copy link
Copy Markdown
Author

/to @jridgewell

*/
this.historyQueue_ = [];

/** @private @const {!Function} */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @private @const {!Function} */
/** @private @const {function()} */

this.debouncedFlushHistoryQueue_ = debounce(
this.win_,
() => this.flushHistoryQueue_(),
1000
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on how quickly these calls are coming in, we may never replace the history. Eg, if a slidechange happens every .5s, this debounce will never trigger (it's waiting for 1s to pass since the last call before invoking).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but I think this is not a big deal in practice since it only affects users that close the page very quickly after a setState action.

this.historyQueue_.push({op: HistoryOp.PUSH, data, onPop});
// Immediately flush queue on "push" to avoid adding latency to
// the browser "back" functionality.
this.flushHistoryQueue_();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a way to cancel the debounced timer, if any is pending.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's worth the extra code since flushing an empty queue is harmless.

// Skip consecutive "replace" operations.
const next = this.historyQueue_[i + 1];
if (next && next.op === HistoryOp.REPLACE) {
continue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this could be done better at the push side, which'll prevent this queue from getting massive.

const last = getLast(this.historyQueue_);
if (last && last.op === HistoryOp.REPLACE) {
  last.data = data;
} else {
  this.historyQueue_.push({ op: HistoryOp.REPLACE, data });
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

// may contain user data e.g. form input.
return this.viewer_.isTrustedViewer().then(trusted => {
return trusted ? data : null;
return trusted ? getData() : undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defering the copy like this creates a slight change of behavior, since we'll now copy the data after isTrustedViewer resolves instead of before.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, this is probably an unnecessary optimization since it only affects untrusted viewers. Removed.

// Collapse if consecutive "replace" operations.
if (task.op === HistoryOp.REPLACE) {
const lastTask = this.historyQueue_[this.historyQueue_.length - 1];
if (lastTask && lastTask.op === HistoryOp.REPLACE) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Check that there's at least 1 queued item before, instead of doing a missed lookup.

@dreamofabear dreamofabear merged commit fb19bc7 into ampproject:master Aug 15, 2019
@dreamofabear dreamofabear deleted the bind-history-rate-limit branch August 15, 2019 22:16
westonruter added a commit to westonruter/amphtml that referenced this pull request Aug 17, 2019
…cript-img-with-http-protocol

* 'master' of github.com:ampproject/amphtml: (1326 commits)
  Fix and enable e2e tests for AMPHTML ads FIE rendering mode (ampproject#23995)
  🏗 Update WorkerDOM to 0.17.0 (ampproject#24024)
  Make DocInfo.pageViewId64 async (ampproject#23998)
  🐛 Updates amp-sidebar in amp-story  (ampproject#23956)
  Revert "Revert "📖Update documentation for carousel 0.2 (ampproject#23840)" (ampproject#23967)" (ampproject#24016)
  🔥 Revert "📈 Initial StorySpec Implementation (ampproject#23030)" (ampproject#24013)
  Extension skeleton code for payment widgets (ampproject#23045)
  🏗🐛 Don't call `travisBuildNumber()` in the global scope (ampproject#24021)
  Remove suppressTypes from amp-mustache. (ampproject#23993)
  🐛 Move `terser` from `dependencies` to `devDependencies` (ampproject#24018)
  Revert "Revert "Set the new loaders experiment to 1% of traffic. (ampproject#23780)" (ampproject#23963)" (ampproject#24014)
  SwG release 0.1.22.63 (ampproject#23997)
  Resolve navTiming variable earlier if possible (ampproject#23580)
  🏗 Don't run all the runtime tests for validator-only changes (ampproject#24010)
  Collect document ready signal (ampproject#23981)
  Validator rollup (ampproject#24000)
  Remove flaky story branching test. (ampproject#23994)
  Include amp-base-carousel in amp-carousel's build. (ampproject#23984)
  Partial validator rollup (ampproject#23996)
  amp-bind: Rate-limit history operations (ampproject#23938)
  ...
dreamofabear pushed a commit that referenced this pull request Aug 30, 2019
dreamofabear pushed a commit that referenced this pull request Sep 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error: Attempt to use history.replaceState() more than 100 times per 30.000000 seconds

3 participants