【问题标题】:How would I make ajax wait with setTimeout within a switch case如何在 switch 案例中使用 setTimeout 让 ajax 等待
【发布时间】:2016-06-27 21:58:52
【问题描述】:

如何让 ajax 等待 20 秒再显示下一条聊天行。我想要做的是让 ajax 在发送下一条聊天线之前等待几秒钟。

例如,假设有 3 个用户登录并且他们三个人同时提交了一个聊天。假设 user1 发送了“Hi”,user2 发送了“hello”,user3 发送了“okay”。他们三个同时提交,这个程序的作用是在一定的时间间隔内获取它在数据库中找到的所有聊天记录并打印出来。我想要它做的是等待几秒钟,然后打印它在数据库中读取的所有数据。

例如,它应该以不同的时间间隔打印来自 user1、user2 和 user3 的输入

'嗨'
//等待30秒然后打印下一条消息 '你好'
//再等待30秒然后打印下一条消息 '好的'
//如果在此时间间隔内有更多消息,则再等待 30 秒

index.html

<body>

    <div id="chatContainer">

        <div id="chatTopBar" class="rounded"></div>
        <div id="chatLineHolder"></div>

        <div id="chatUsers" class="rounded"></div>
        <div id="chatBottomBar" class="rounded">
            <div class="tip"></div>

            <form id="loginForm" method="post" action="">
                <input id="name" name="name" class="rounded" maxlength="16" />
                <input id="email" name="email" class="rounded" />
                <input type="submit" class="blueButton" value="Login" />
            </form>

            <form id="submitForm" method="post" action="">
                <input id="chatText" name="chatText" class="rounded" maxlength="255" />
                <input type="submit" class="blueButton" value="Submit" />
            </form>

        </div>

    </div>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script src="js/jScrollPane/jquery.mousewheel.js"></script>
    <script src="js/jScrollPane/jScrollPane.min.js"></script>
    <script src="js/script.js"></script>
</body>

script.js

$(document).ready(function(){

    // Run the init method on document ready:
    chat.init();

});

var chat = {

    // data holds variables for use in the class:

    data : {
        lastID      : 0,
        noActivity  : 0
    },

    // Init binds event listeners and sets up timers:

    init : function(){


        // Converting the #chatLineHolder div into a jScrollPane,
        // and saving the plugin's API in chat.data:

        chat.data.jspAPI = $('#chatLineHolder').jScrollPane({
            verticalDragMinHeight: 12,
            verticalDragMaxHeight: 12
        }).data('jsp');

        // We use the working variable to prevent
        // multiple form submissions:

        var working = false;

        // Self executing timeout functions

        (function getChatsTimeoutFunction(){
            chat.getChats(getChatsTimeoutFunction);
        })();

        (function getUsersTimeoutFunction(){
            chat.getUsers(getUsersTimeoutFunction);
        })();

    },


    // The render method generates the HTML markup 
    // that is needed by the other methods:

    render : function(template,params){

        var arr = [];
        switch(template){
            case 'loginTopBar':
                arr = [
                '<span><img src="',params.gravatar,'" width="23" height="23" />',
                '<span class="name">',params.name,
                '</span><a href="" class="logoutButton rounded">Logout</a></span>'];
            break;

            case 'chatLine':
                arr = [
                    '<div class="chat chat-',params.id,' rounded"><span class="gravatar"><img src="',params.gravatar,
                    '" width="23" height="23" onload="this.style.visibility=\'visible\'" />','</span><span class="author">',params.author,
                    ':</span><span class="text">',params.text,'</span><span class="time">',params.time,'</span></div>'];
//////////////////////////////////////////////////
// I have tried to do a setTimeout here but it does not delay the message
//////////////////////////////////////////////////
            break;

            case 'user':
                arr = [
                    '<div class="user" title="',params.name,'"><img src="',
                    params.gravatar,'" width="30" height="30" onload="this.style.visibility=\'visible\'" /></div>'
                ];
            break;
        }

        return arr.join('');

    },

    // The addChatLine method ads a chat entry to the page

    addChatLine : function(params){

        // All times are displayed in the user's timezone

        var d = new Date();
        if(params.time) {

            // PHP returns the time in UTC (GMT). We use it to feed the date
            // object and later output it in the user's timezone. JavaScript
            // internally converts it for us.

            d.setUTCHours(params.time.hours,params.time.minutes);
        }

        params.time = (d.getHours() < 10 ? '0' : '' ) + d.getHours()+':'+
                      (d.getMinutes() < 10 ? '0':'') + d.getMinutes();

        var markup = chat.render('chatLine',params),
            exists = $('#chatLineHolder .chat-'+params.id);

        if(exists.length){
            exists.remove();
        }

        if(!chat.data.lastID){
            // If this is the first chat, remove the
            // paragraph saying there aren't any:

            $('#chatLineHolder p').remove();
        }

        // If this isn't a temporary chat:
        if(params.id.toString().charAt(0) != 't'){
            var previous = $('#chatLineHolder .chat-'+(+params.id - 1));
            if(previous.length){
                previous.after(markup);
            }
            else chat.data.jspAPI.getContentPane().append(markup);
        }
        else chat.data.jspAPI.getContentPane().append(markup);

        // As we added new content, we need to
        // reinitialise the jScrollPane plugin:

        chat.data.jspAPI.reinitialise();
        chat.data.jspAPI.scrollToBottom(true);

    },

    // This method requests the latest chats
    // (since lastID), and adds them to the page.

    getChats : function(callback){
        $.tzGET('getChats',{lastID: chat.data.lastID},function(r){

            for(var i=0;i<r.chats.length;i++){
                chat.addChatLine(r.chats[i]);
            }

            if(r.chats.length){
                chat.data.noActivity = 0;
                chat.data.lastID = r.chats[i-1].id;
            }
            else{
                // If no chats were received, increment
                // the noActivity counter.

                chat.data.noActivity++;
            }

            if(!chat.data.lastID){
                chat.data.jspAPI.getContentPane().html('<p class="noChats">No chats yet</p>');
            }

            // Setting a timeout for the next request,
            // depending on the chat activity:

            var nextRequest = 1000;

            // 2 seconds
            if(chat.data.noActivity > 3){
                nextRequest = 2000;
            }

            if(chat.data.noActivity > 10){
                nextRequest = 5000;
            }

            // 15 seconds
            if(chat.data.noActivity > 20){
                nextRequest = 15000;
            }

            setTimeout(callback,nextRequest);
        });
    },

};

// Custom GET & POST wrappers:

$.tzPOST = function(action,data,callback){
    $.post('php/ajax.php?action='+action,data,callback,'json');
}

$.tzGET = function(action,data,callback){
    $.get('php/ajax.php?action='+action,data,callback,'json');
}

// A custom jQuery method for placeholder text:

$.fn.defaultText = function(value){

    var element = this.eq(0);
    element.data('defaultText',value);

    element.focus(function(){
        if(element.val() == value){
            element.val('').removeClass('defaultText');
        }
    }).blur(function(){
        if(element.val() == '' || element.val() == value){
            element.addClass('defaultText').val(value);
        }
    });

    return element.blur();
}

ajax.php

<?php

/* Database Configuration. Add your details below */

$dbOptions = array(
    'db_host' => '',
    'db_user' => '',
    'db_pass' => '',
    'db_name' => ''
);

/* Database Config End */


error_reporting(E_ALL ^ E_NOTICE);

require "classes/DB.class.php";
require "classes/Chat.class.php";
require "classes/ChatBase.class.php";
require "classes/ChatLine.class.php";
require "classes/ChatUser.class.php";

session_name('webchat');
session_start();

if(get_magic_quotes_gpc()){

    // If magic quotes is enabled, strip the extra slashes
    array_walk_recursive($_GET,create_function('&$v,$k','$v = stripslashes($v);'));
    array_walk_recursive($_POST,create_function('&$v,$k','$v = stripslashes($v);'));
}

try{

    // Connecting to the database
    DB::init($dbOptions);

    $response = array();

    // Handling the supported actions:

    switch($_GET['action']){

        case 'login':
            $response = Chat::login($_POST['name'],$_POST['email']);
        break;

        case 'checkLogged':
            $response = Chat::checkLogged();
        break;

        case 'logout':
            $response = Chat::logout();
        break;

        case 'submitChat':
            $response = Chat::submitChat($_POST['chatText']);
        break;

        case 'getUsers':
            $response = Chat::getUsers();
        break;

        case 'getChats':
            $response = Chat::getChats($_GET['lastID']);
        break;

        default:
            throw new Exception('Wrong action');
    }

    echo json_encode($response);
}
catch(Exception $e){
    die(json_encode(array('error' => $e->getMessage())));
}

?>

Chat.class.php

<?php

/* The Chat class exploses public static methods, used by ajax.php */

class Chat{


    public static function getChats($lastID){
        $lastID = (int)$lastID;

        $result = DB::query('SELECT * FROM webchat_lines WHERE id > '.$lastID.' ORDER BY id ASC');

        $chats = array();
        while($chat = $result->fetch_object()){

            // Returning the GMT (UTC) time of the chat creation:

            $chat->time = array(
                'hours'     => gmdate('H',strtotime($chat->ts)),
                'minutes'   => gmdate('i',strtotime($chat->ts))
            );

            $chat->gravatar = Chat::gravatarFromHash($chat->gravatar);

            $chats[] = $chat;
        }

        return array('chats' => $chats);
    }

    public static function gravatarFromHash($hash, $size=23){
        return 'http://www.gravatar.com/avatar/'.$hash.'?size='.$size.'&amp;default='.
                urlencode('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size='.$size);
    }
}


?>

【问题讨论】:

  • 您想要这样做的确切原因是什么?老实说,我认为您的聊天客户端的用户体验会非常糟糕(轻描淡写)......
  • 我想在将消息显示给用户之前将其数据保存在其他地方。但它需要一些时间才能加载并保存在其他页面中。 @BarryMeijer
  • 在这种情况下,问题出在其他地方......你应该拆分一些东西。对于我自己的一个项目,我曾经不得不构建一个像聊天客户端这样的 Omegle。当用户发布一条消息时,它会保存在数据库中,另一段代码每 500 毫秒检查一次新消息。我的观点是,超过 1 秒就太多了……
  • @BarryMeijer 现在我只想让它在显示消息之前等待几秒钟。过去一周我一直在尝试这个,但没有成功。我尝试制作将数据发送到 php 文件然后休眠的 ajax,但它不尊重 sleep 方法并继续运行等
  • Javascript 不支持睡眠方法。每个代码 sn-p 在另一个代码可以运行之前在一个线程中运行完成。对 setTimeout 的调用只是将提供的函数排入队列并继续执行下一行代码而无需等待。听起来像是算法设计问题。

标签: javascript php jquery ajax


【解决方案1】:

如果我对问题的理解正确,您希望在屏幕上显示每条聊天消息,间隔 30 秒。如果是这种情况,您可以在 for 循环中设置超时。见下面代码 sn-p 中的 cmets:

// This method requests the latest chats
// (since lastID), and adds them to the page.

getChats : function(callback){
    $.tzGET('getChats',{lastID: chat.data.lastID},function(r){

        /***** REPLACE THIS
        for(var i=0;i<r.chats.length;i++){
            chat.addChatLine(r.chats[i]);
        }
        *****/


        /***** WITH THIS *****/
        for (var i = 0; i <= r.chats.length; i++) {
            setTimeout(function(x) {
                return function() {
                    console.log(x);
                    chat.addChatLine(r.chats[x]);
                };
            }(i), 30000*i);
        }
        /***** END EXAMPLE *****/


        if(r.chats.length){
            chat.data.noActivity = 0;
            chat.data.lastID = r.chats[i-1].id;
        }
        else{
            // If no chats were received, increment
            // the noActivity counter.

            chat.data.noActivity++;
        }

        if(!chat.data.lastID){
            chat.data.jspAPI.getContentPane().html('<p class="noChats">No chats yet</p>');
        }

        // Setting a timeout for the next request,
        // depending on the chat activity:

        var nextRequest = 1000;

        // 2 seconds
        if(chat.data.noActivity > 3){
            nextRequest = 2000;
        }

        if(chat.data.noActivity > 10){
            nextRequest = 5000;
        }

        // 15 seconds
        if(chat.data.noActivity > 20){
            nextRequest = 15000;
        }

        setTimeout(callback,nextRequest);
    });
},

由于 for 循环中的普通 setTimeout 函数只会一遍又一遍地输出相同的索引,因此我们需要将原始匿名函数包装在另一个中。在外部匿名函数中,我们接受一个参数 x 并将 x 传递给 chat.addChatLine()。我们在每个循环期间立即执行外部函数并将 i 的值传递给它。然后,外部函数返回要用于 setTimeout() 的原始匿名函数,其中 i 的值在其私有变量 x 中捕获。

【讨论】:

  • 这可能有效,但不能回答如何在switch-case 中完成的问题。如果您可以编辑答案以更好地适应问题,那就太好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 2013-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
相关资源
最近更新 更多