J82
J82

Reputation: 8457

Why is my admin-ajax so slow compared to other sites that also use it?

Here is my site.

If you hover over one of the projects and click the plus icon, the Ajax call goes out and the response returns in 1-4 seconds on average. I'm not understanding why it's so slow compared to a similar site that also uses admin-ajax.php (try hovering/clicking on one of the projects on that site to compare). All of the images called by Ajax are optimized. I also optimized my database tables. I'm not sure what else I can do.

Here is a comparison of the response time of admin-ajax.php from both sites. As you can see, the other site takes 480ms while mine takes 2s:

enter image description here

Here is how I have my Ajax call set up. Sorry, I didn't simplify the code because I think maybe the reason for the delay can only be found in the full code. The actual Ajax call is about halfway down.

(function($) {

    // Function to allow an event to fire after all images are loaded
    $.fn.imagesLoaded = function () {

        var imgs = this.find('img[src!=""]');

        // If there are no images, just return an already resolved promise
        if (!imgs.length) {
            return $.Deferred().resolve().promise();
        }

        // For each image, add a deferred object to the array which resolves when the image is loaded
        var dfds = [];
        imgs.each(function(){

            var dfd = $.Deferred();
            dfds.push(dfd);
            var img = new Image();
            img.onload = function(){dfd.resolve();};
            img.src = this.src;

        });

        // Return a master promise object which will resolve when all the deferred objects have resolved
        // IE - when all the images are loaded
        return $.when.apply($, dfds);

    };

    // Function for additional styling
    function projectStyles() {

        // Check the first slide input
        $('#slider input:first').attr('checked', 'checked');

        $('#project-wrapper').addClass('activated');

        // Make the articles grey again after activation
        $('article.project').addClass('grayscale grayscale-fade').css('opacity', '0.4');

        // CSS effects
        $('.post-container').addClass('fadeInUp');
        $('.close-button').addClass('fadeInDown');

        // Remove pesky, sticky 'hover' class
        $('article.project').removeClass('hover');
    }

    // Make the max-height of the container exact for a smoother transition
    function matchContainerHeight() {
        var heightHandler = function() {
            var containerHeight = $('#project-container').outerHeight();
            $('#project-wrapper.activated').css('max-height', containerHeight);
        };
        setTimeout(heightHandler, 100);
        $(window).on('resize', heightHandler);
    }

    // Open the project container
    function openProject() {

        var post_id = $(this).data('id'), // data-id attribute for .post-link
            ajaxURL = site.ajaxURL; // Ajax URL localized from functions.php

        // Add a loading icon
        $('<span class="loading-icon"></span>').insertBefore(this);

        // Add the 'active' class to make sure the div stays dark while loading
        $(this).closest('article.project').addClass('active hover-sticky');

        // Make all the articles grey when an article is clicked
        $('article.project').addClass('grayscale grayscale-fade grayscale-sticky').css('opacity', '0.4');

        // No hover on images while a project is loading
        $('article.project img').addClass('nohover');

        // Remove all corner ribbons
        $('article').removeClass('current');
        $('.corner-ribbon').remove();

        // Add a corner ribbon to note the current activated project
        $(this).closest('article.project').removeClass('active').addClass('current');
        $('<div class="corner-ribbon">Current</div>').prependTo('article.current');

        // Call Ajax
        $.ajax({
            type: 'POST',
            url: ajaxURL,
            data: {'action': 'load-content', post_id: post_id },
            success: function(response) {

                // Wait until all images are loaded
                $('#project-container').html(response).imagesLoaded().then(function() {

                    // Fire again to rearrange the slide in the DOM
                    resize();

                    // Remove all 'hover' classes
                    $('article.project').removeClass('hover-sticky grayscale-sticky');
                    $('article.project img').removeClass('nohover');

                    // Remove the loading icon
                    $('.loading-icon').remove();

                    // If the user has scrolled...
                    if ($(window).scrollTop() !== 0) {

                        // First scroll the page to the top
                        $('html, body').animate({
                            scrollTop : 0
                        },400, function() {

                            matchContainerHeight();
                            projectStyles();

                        });

                    // If the user has not scrolled...
                    } else {

                        matchContainerHeight();
                        projectStyles();

                    }

                    return false;
                });
            }
        });
    }

    // User event
    $('#content').on('click', '.post-link', function(e) {
        e.preventDefault();

        var projectTitle = $(this).data('title'), // data-title attribute for .post-link
            projectSlug = $(this).data('slug'); // data-slug attribute for .post-link

        // Calls openProject() in context of 'this' (.post-link)
        openProject.call(this);

        $('head').find('title').text(projectTitle + ' | Keebs');
    });

})(jQuery);

Here is the Ajax response file. I'm using the ACF plugin, but I tried the response without any of the ACF fields and the wait time was the same. I also tried removing everything within the my_load_ajax_content() function but the wait time was still the same as well. So I'm guessing something else is causing the long wait time. I also tried GET instead of POST but the response time was around the same:

<?php
/**
 * Ajax functions
 */

// Return the post content to the AJAX call
function my_load_ajax_content () {

    $args = array(
        'p' => $_POST['post_id'],
        'post_type' => 'projects'
        );

    $post_query = new WP_Query( $args );
    while( $post_query->have_posts() ) : $post_query->the_post(); ?>

    <div class="post-container">
        <div id="project-left-content">
            <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
            <?php the_content(); ?>

            <?php if( get_field('client') ): ?>
                <div class="client">
                    Client(s): <?php the_field('client'); ?>
                </div>
            <?php endif; ?>

            <div class="project-cats">
                <?php
                    $cat_names = wp_list_pluck( get_the_category(), 'cat_name');
                    echo join( ', ', $cat_names );
                ?>
            </div>

            <?php if( get_field('url') ): ?>
                <div class="project-link">
                    <a class="first after" href="http://<?php the_field('url'); ?>" target="_blank"><?php the_field('url'); ?></a>
                </div>
            <?php endif; ?>
        </div>
        <div id="project-right-content">

            <?php if( have_rows('slides') ): ?>

                <div id="slider">

                    <!-- Slider Setup -->
                    <?php if( have_rows('slides') ):
                        $slideNumber = 0;
                        while ( have_rows('slides') ) : the_row();
                        $slideNumber++;
                    ?>

                        <input type="radio" name="slider" id="slide<?php echo $slideNumber; ?>">

                    <?php endwhile;endif; ?>

                    <!-- Slide -->
                    <?php if( have_rows('slides') ): ?>
                        <div id="slides">
                            <div id="overflow">
                                <div class="inner">

                                    <?php if( have_rows('slides') ):
                                    while ( have_rows('slides') ) : the_row();

                                        $slideImage = get_sub_field('slide_image');
                                    ?>

                                    <article>
                                        <img src="<?php echo $slideImage; ?>" alt="<?php the_title(); ?>">
                                    </article>

                                    <?php endwhile;endif; ?>

                                </div><!-- #inner -->
                            </div><!-- #overflow -->
                        </div><!-- #slides -->

                    <?php endif; ?>

                    <!-- Controls -->
                    <?php if( have_rows('slides') ):
                        $slideNumber = 0;
                    ?>
                        <div id="active">

                            <?php while ( have_rows('slides') ) : the_row();
                                $slideNumber++;
                            ?>
                                <label for="slide<?php echo $slideNumber; ?>"></label>
                            <?php endwhile; ?>

                        </div><!-- #active -->
                    <?php endif; ?>
                </div><!-- #slider -->
            <?php endif; ?>
        </div><!-- #project-right-content -->
    </div><!-- .post-container -->

    <?php
    endwhile;
    wp_die();
}

add_action ( 'wp_ajax_nopriv_load-content', 'my_load_ajax_content' ); // when the user is logged in
add_action ( 'wp_ajax_load-content', 'my_load_ajax_content' ); // when the user is not logged in

Does anybody see something that I should be doing differently?

Upvotes: 0

Views: 3667

Answers (3)

Vishal Wadhawan
Vishal Wadhawan

Reputation: 1085

I would want to suggest you that rather then echoing HTML code from your php file you just return the main data(only raw information based on the click) as json response and then generate the html tags based on that and append it . Creating HTML from javascript is much faster than echoing HTML , specially during ajax call. I am sure if you do this you can get quite fast performance. Any big or large site they dont send HTML in ajax response. Majorly pure json response containing the key information is echoed. And on basis of that the divs are generated to load the section faster.

Upvotes: 0

Chris Gunawardena
Chris Gunawardena

Reputation: 6468

Looks like your site is hosted on dreamhost and most likely on shared hosting offering they have. The other website you mentioned looks like it is hosted on its own VPS. Shared hosting is often known for their slow database performance.

Your best option might be to use a caching solution like 'WP Super Cache' or 'W3 Total Cache' that saves the webpage to memory or disk on first request and serves from there on subsequent requests bypassing the database.

These are both wordpress plugin and can be easily installed from the admin plugins section.

https://wordpress.org/plugins/wp-super-cache/ https://wordpress.org/plugins/w3-total-cache/

Other option is trying to create indexes on the databse for faster searching. You could also look at using a small VPS (AmazonEC2 free tier or $5/month from digital ocean etc) if you know how to install Apache/mysql etc.

Upvotes: 6

Laurie Williams
Laurie Williams

Reputation: 69

Can I make a suggestion?

Instead of defining your function like this:

(function($) 

try something like this:

jQuery(document).ready(function($) {

   $('selector').whatever();

  })

I'm still learning Wordpress myself but I have found that defining the function as using jQuery can make a difference. I think this is because Wordpress is unsure of which library you want to use.

Upvotes: -3

Related Questions