feature request: debounce on search form !!!

Posted in: Newspaper
Post count: 40

Hi,

just found out what was taking my server threw hell… it’s the search form that send a post on every letter tipped !!!

please, please add lodash debounce on this
it’s nothing to do
check this
https://css-tricks.com/debouncing-throttling-explained-examples/

please !!!

added to the fact that call is done via POST makes it hell to cache it!
and it really deserves caching !!

so changing it to a GET so cdn can cache it would be marvelous!

thanks

  • This topic was modified 6 years by cantoute.
Post count: 35449

Hello,

I add this suggestion on our list for coming improvements.

Thank you for your suggestion!

Post count: 40

It’s because our users seem to love the search function that I’m going to need this badly… happy to help if possible, because the debounce stuff really are 4 dummy lines to add and they really make a difference on usability and server load.

It’ll make search display much faster then calling on every keypress.

With 140k posts and over 50k daily users… it’s really to be hard on server

Thanks

Post count: 35449

Hello,

Your suggestion was add on our feature list and from now on is the developer choose when it will be implement it in the theme.

Thank you!

Post count: 40

Hi Calin,

I was very busy with migrating that 140k pages site, so I didn’t take the time to look into this until now.

So I just prettified the script_for_front.js and had a quick look and the fix seams real easy.

somewhere around line 350 I see this


a.jqueryObj.find(".tdb-head-search-form-input").keydown(function (b)
{
if (b.which && 39 === b.which || b.keyCode && 39 === b.keyCode || b.which && 37 === b.which || b.keyCode && 37 === b.keyCode) tdbSearch.set_input_focus(a);
else
{
if (b.which && 13 === b.which || b.keyCode && 13 === b.keyCode) return b =
a.jqueryObj.find(".tdb-aj-cur-element"), 0 < b.length ? window.location = b.find(".entry-title a").attr("href") : jQuery(this).parent().parent().submit(), !1;
if (b.which && 40 === b.which || b.keyCode && 40 === b.keyCode) return tdbSearch.move_prompt_down(a), !1;
if (b.which && 38 === b.which || b.keyCode && 38 === b.keyCode) return tdbSearch.move_prompt_up(a), !1;
(b.which && 8 === b.which || b.keyCode && 8 === b.keyCode) && 1 === jQuery(this).val().length && a.jqueryObj.find(".tdb-aj-search").empty();
tdbSearch.set_input_focus(a);
setTimeout(function ()
{
tdbSearch.do_ajax_call(a)
},
100);
return !0
}
});

looking just on the last few lines

replacing this

setTimeout(function ()
{
tdbSearch.do_ajax_call(a)
},
100);

by that

debounce(
setTimeout(function () {
tdbSearch.do_ajax_call(a)
}, 0),
250
);

first you would need this https://davidwalsh.name/javascript-debounce-function
actually coming from an old version of underscore (it works!)

function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};

this is the actual up to date function on https://github.com/jashkenas/underscore/blob/master/underscore.js
but perhaps underscore can be useful to have in such a project

I see here that _.debounce requires _.delay who needs restArguments
this could be the “light” way that does the trick too

_ = _ || {};

_.debounce = function(func, wait, immediate) {
var timeout, result;

var later = function(context, args) {
timeout = null;
if (args) result = func.apply(context, args);
};

var debounced = restArguments(function(args) {
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(this, args);
} else {
timeout = _.delay(later, wait, this, args);
}

return result;
});

debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};

return debounced;
};

_.delay = restArguments(function(func, wait, args) {
return setTimeout(function() {
return func.apply(null, args);
}, wait);
});

// Some functions take a variable number of arguments, or a few expected
// arguments at the beginning and then a variable number of values to operate
// on. This helper accumulates all remaining arguments past the function’s
// argument length (or an explicit
startIndex), into an array that becomes
// the last argument. Similar to ES6’s "rest parameter".
var restArguments = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
var length = Math.max(arguments.length - startIndex, 0),
rest = Array(length),
index = 0;
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};

Perhaps you all ready have underscore? but didn’t spot it in that js

… it’s got nice goodies and comes handy 🙂 (17.6 KB not so bad ?)

hope this comes helpful, have a nice day.

oups editing code here is dangerous ö

  • This reply was modified 6 years by cantoute. Reason: forgot restArguments
  • This reply was modified 6 years by cantoute. Reason: forgot restArguments
Post count: 40

perhaps on this https://pastebin.com/k0PRwzzC it’s more readable… but not much more :-/ sorry

Post count: 40

no deed for the setTimeout… me dummy… the debounce will async your call 🙂

debounce(
tdbSearch.do_ajax_call(a),
250
);

and the old debounce function or adding underscore
it gets messy to take bits of the more recent _ versions…

  • This reply was modified 6 years by cantoute.
Post count: 40

looks a bit better here… sorry for all the noise

https://pastebin.com/5U1uSyFT

Post count: 40

I finally found a way to hack it in… to give the server a breath

https://pastebin.com/LtvHqZM8

jQuery(function() {
jQuery('.tdb-head-search-form-input').on('keydown', function(e) {
if (typeof debounce_do_ajax_call === "undefined") {
console.log('tdbSearch.do_ajax_call override');

tdbSearch.original_td_do_ajax_call = tdbSearch.do_ajax_call;

// as hacked out of context, needed to hook context or debounce would trigger on each call
debounce_do_ajax_call = debounce(tdbSearch.original_td_do_ajax_call, 1500)

tdbSearch.do_ajax_call = debounce_do_ajax_call
}
});
});

// https://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};

Post count: 35449

Hello,

Thank you for sharing with us your results and implementation for this request; this implementation would be examined by our developers too.

Thank you for your solution!

Post count: 40

The webiste I did with your theme has gone from small trafic to become nº1 in tennis in europe… thanks to your work !!

But that means that for Roland Garros I could have to handle over 500k daily visitors (we are yet over 70k)
It’s not that big… I have other site running 2M (not wp tho)
As the site uses infinit scroll… caching even of 3s would help

I coud suggest a very simple change that could change the deal about caching (the site is behind varnish)

php side have all ajax $_POST changed to $_REQUEST

then I could fiddle to change all ajax POST to { method:’GET’, cache:false }

it adds a &_=134567 that can be removed from url in varnish and then hit a common cache

… no rush, just clues 🙂

  • This reply was modified 6 years by cantoute.
Post count: 40

and here i took things one step further but the result is almost copy paste for devs

Just you wouldn’t have to put debounce_ajax_call in ‘window’ context, I was forced to it because my context is .on(‘foncsin’) (out of tdAjaxSearch object)
so in this hack i just debounce the actual ajax request (and not the do_ajax_call) that is changed to ‘GET’ (and removing the setTimeout)

line 19 there is
tdAjaxSearch.process_ajax_response_mob(b)

if you change it to
tdAjaxSearch.process_ajax_response_mob(b, a) // a being here the search term

then in function process_ajax_response_mob() you have the term without having to read the response 🙂

https://pastebin.com/cL3SfhVf

I was just playing around to look for ways of making life easier in there.

hope it can help

  • This reply was modified 6 years by cantoute.
Post count: 40

being here I had an other issue with the megamenu offsetting itself halfway threw the page when post had a tweet

this was the fix


/* fix megamenu offset when post has a tweet */
(function($){
    $(window).load(function() {
        $(this).trigger('resize')
    })
})(jQuery)
Post count: 35449

Hello,

Thank you for sharing with us your improvements, I already send the link to our developers to inspect your suggestion and implementation.

Thank you for sharing with us your work!

Viewing 14 posts - 1 through 14 (of 14 total)
The forum ‘Newspaper’ is closed to new topics and replies.