2
\$\begingroup\$

An easy to use type feature that uses the placeholder attribute and setTimer to give the effect of a user typing. Helpful if you need to draw attention to the search box field.

I'm looking to know if this type of implementation would be a performance impact or cause browser lag. Help in making this more condensed would also be helpful. I was thinking about using $.extend, but leaned away. Any reason why I shouldn't make this a jquery plugin?

https://jsfiddle.net/googabeast/jsepy3ed/

obj = {
    searchTxt: [
        "Welcome. What are you searching for? ",
        "Something else to type out "
        "Note the space at the end -> "
    ],
    hasFocus:false
}

if(obj.searchTxt !== null && obj.searchTxt !== "undefined"){
    var i = 0, ct = 0; obj.typeIt;

    function type(){
        obj.typeIt = obj.searchTxt[ct].slice(0, ++i);
        if(obj.typeIt === obj.searchTxt[ct]){
            i = 0;
            if(ct === obj.searchTxt.length-1){
                ct = 0;
            }else{
                ++ct;
            }
            return;
        };
        $(".searchBox").attr("placeholder", obj.typeIt);
        setTimeout(type, 80);
    };
    type();


    $(window).on({
        focus: function(){ obj.hasFocus = true; },
        blur: function(){ obj.hasFocus = false; }
    }).trigger("focus");

    setInterval(function(){
        if(obj.hasFocus){
            type();
        };
    }, 10000);
};
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Performance Considerations

As the code stands now, every time the type function is invoked (that is, every 80 milliseconds) the code will parse the DOM looking for any elements with the searchBox class.

You can improve the code's efficiency by moving that expensive operation outside the function.

var i = 0, ct = 0, searchBox = $(".searchBox"); obj.typeIt;

function type(){
    // ...
    searchBox.attr("placeholder", obj.typeIt);
    // ...
};

If you know there'll only be one element with the searchBox class, you could improve its efficiency a step further by using the native document.querySelector method.

var i = 0, ct = 0, searchBox = document.querySelector(".searchBox"); obj.typeIt;

function type(){
    // ...
    searchBox.setAttribute("placeholder", obj.typeIt);
    // ...
};

Timeout/Interval Overlap

This one's not a biggie, but it's good to be aware of when working with setTimeout and setInterval.

Your interval function is running every 10 seconds to invoke type, while within the type function a timeout is running every 80 milliseconds to invoke type again (until the end of the search text short circuits that behavior).

If the code happens to be in the middle of writing out some search text when the 10-interval kicks in, you'll see some unusual behavior: multiple characters will be written within 80 milliseconds.

For something like this, that's probably not a major issue (you'll only see it happen when the search text is abnormally long or the interval time is abnormally short), but if you want to account for it, you can eliminate setInterval altogether. Instead, you can put a 10-second timeout in the "dead end" branch of the type function (the if block that short-circuits the 80-ms timeout upon reaching the end of the search text), just before the return statement.

function type(){
    obj.typeIt = obj.searchTxt[ct].slice(0, ++i);
    if(obj.typeIt === obj.searchTxt[ct]){
        i = 0;
        if(ct === obj.searchTxt.length-1){
            ct = 0;
        }else{
            ++ct;
            /* This replaces the setInterval call later in your code: */
            setTimeout(function(){
                if(obj.hasFocus){
                    type();
                }
            },10000);
        }
        return;
    };
    $(".searchBox").attr("placeholder", obj.typeIt);
    setTimeout(type, 80);
};

This ensures that type is invoked every 80 milliseconds while typing out the search text, and then every 10-seconds between search texts.

Another option is to use the clearTimeout method to make sure you don't have duplicate timeouts for the same function call running in parallel.

// define a timeout variable
var i = 0, ct = 0, timeout; obj.typeIt;

function type(){
    // ...
     if(timeout){clearTimeout(timeout);} // eliminate duplicate timeouts
     timeout = setTimeout(type, 80);
}

This is useful if there are multiple entry points for the type function, such as if you were to invoke it from the window's onFocus event.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for the review! I attempted your suggestions and was able to devise this working solution. jsfiddle.net/googabeast/jsepy3ed/1 Onlything is now when you leave window focus and come back it is re-running the function. Without the typeit() function in the window.focus the typeit() function will never run again when window does have focus jsfiddle.net/googabeast/jsepy3ed/2 Lastly tried to make typeIt a self executing function and that just causes it to run once as well. jsfiddle.net/googabeast/jsepy3ed/3 \$\endgroup\$
    – googabeast
    Nov 1, 2016 at 18:32
  • \$\begingroup\$ See my updated review. The clearTimeout function can be used to prevent duplicate timeouts from being queued up simultaneously, so you could safely slip the type() invocation in your onFocus event again. \$\endgroup\$
    – Thriggle
    Nov 1, 2016 at 18:50
  • \$\begingroup\$ Ahhh... completely skipped over that idea. Thanks! \$\endgroup\$
    – googabeast
    Nov 2, 2016 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.