Comment moderation is handy, but it’s annoying from a non-spammers point of view when it appears that the submission has simply vanished. My solution is to add an extra function to wp-includes/template-function-comments.php and a couple of lines in the wp-comments.php file that show a placeholder for pending comments with the time and date of submission (to help prevent abuse such as links in place of a user name there is nothing shown that was typed by the commenter).

Add the following function to wp-includes/template-function-comments.php:

function comment_approved() {
    global $comment;
    return ($comment->comment_approved);
}

Then change the line that fetches the comments in wp-comments.php to fetch all comments regardless of status:

$comments = $wpdb->get_results("SELECT * FROM $tablecomments WHERE
    comment_post_ID = '$id'
    ORDER BY comment_date");

and finally change the main comment display loop to output a placeholder message:

<?php foreach ($comments as $comment) { ?>
    <li id="comment-<?php comment_ID() ?>">
    <?php if (comment_approved() == 1) { comment_text() ?>
        <p><cite><?php comment_type(); ?> <?php _e("by"); ?>
        <?php comment_author_link() ?> &#8212; <?php comment_date() ?>
        @ <a href="#comment-<?php comment_ID() ?>"> 
        <?php comment_time() ?></a></cite>
        <?php edit_comment_link(__("Edit This"), ' |'); ?></p>
    <?php } else { ?>
        [Comment pending approval]
        <p><cite><?php comment_type(); ?> &#8212; <?php comment_date() ?>
        @ <a href="#comment-<?php comment_ID() ?>">
        <?php comment_time() ?></a></cite>
    <?php } ?>
    </li>
<?php } // end for each comment ?>