如何通过jQuery Ajax加快大数据提交时的HTTP响应接收?

8 投票
1 回答
2902 浏览
提问于 2025-04-17 05:37

问题: 使用 python webapp2 和 jQuery Ajax 时,接收大文本数据的响应非常慢(1.7MB 的数据往返需要超过 10 分钟)。

提问: 这是什么原因?怎么改善呢?有没有什么有效的方法可以把大文本分成小块,避免“浏览器卡死”的问题?

背景: 我正在学习用 python 做网页编程,使用的是 webapp2 和 Google App Engine。我想用 jQuery Ajax 创建一个“你输入什么就能看到什么”的编辑区,类似于 stackoverflow 的帖子编辑器:wmd-input 和 wmd-preview,它提供实时预览功能。(它会不断显示“草稿已保存”给短文本。另一个例子是 Google Docs 的实时编辑功能。)

我的例子是这样的: 一个文本变化的 jQuery 插件会在每次输入框内容变化时触发 Ajax 请求 ---> Python 后端接收文本并在其上添加一些消息 ---> 然后把文本和消息一起发送回去 ---> jQuery 使用服务器的响应来更新预览文本框(实际上,发送完整的文本内容只是为了测试)。

我的前端代码:

<script type="text/javascript">
function simpleajax() {
        $.ajax({
            type: 'POST'
            ,url: '/simpleajax'
            ,dataType: 'json'
            ,data:{'esid':'#ajaxin','msgin':$('#ajaxin').val()}
            ,cache:false
            ,async:true
            ,success:function (resp){$('#ajaxout').text(resp.msgout);}
            ,error:function (jqXHR, textStatus, errorThrown){
                {$('#ajaxout').text("Ajax Error:"+textStatus+","+errorThrown)}}
        });
    }

$(document).ready(function(){
$('#ajaxin').bind('textchange', function () {
    $('#ajaxstatus').html('<strong color="blue">Typing ...</strong>');
    simpleajax();
    });
});
</script>

我的后端代码:

class simpleajax(BaseReqHandler):
    def get(self):
        content={'pagealert':'simpleAjax get response'}
        self.render_to_response('simpleAjax.html',**content)

    def post(self):
        esid=self.POST['esid']
        msgin=self.POST['msgin']
        msgout="Server noticed element " + esid + " value changed" + " and saved following message: " + msgin
        content={"msgout":msgout}
        self.writeout(content)

测试案例和症状: 本地服务器 + 纯文本数据

把小于 500KB 的纯文本复制粘贴到输入区域:运行得很好。 但是,1.7MB 的文本让浏览器忙了超过 10 分钟,完全没有反应。

比较一下:我把同样的文本粘贴到 stackoverflow 的帖子编辑器,预览立刻就出现了!这次我没有注意到“草稿已保存”的提示。而且这里有一些 JavaScript 代码在判断文本长度。嗯,可能没有涉及到服务器的通信。但这只是个变通办法,并不是解决我问题的办法。(Google Docs 的自动保存功能一定使用了某种技术来解决这个问题!)

Firebug xhr 监控结果:

#Request Headers:
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Content-Length: 2075974
Referer: http://localhost:8080/ajax
Cookie: __utma=111872281.1883490050.1319630129.1319630129.1319637523.2; __utmz=111872281.1319630129.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Pragma: no-cache
Cache-Control: no-cache

#Response Headers:
Server: Development/1.0
Date: Fri, 04 Nov 2011 03:29:05 GMT
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Content-Length: 1790407

#Firebug Timeline:
TimePoints       TimeElapsed      Actions
0                 1ms           DNS Lookup
+1ms              1ms           Connecting
+2ms              82ms          Sending
+84ms            1.03s          Waiting
+1.11s           14m22s         Receiving
+14m23.11s                       Done

有趣的事情:

  1. jQuery Ajax 向服务器发送了 2MB 的数据,而不是 1.7MB 的纯数据。真是个大开销!这可能是因为 Content-Type: application/x-www-form-urlencoded 吗?
  2. 服务器响应需要 1.03 秒,而 jQuery 接收响应却花了 14 分钟!!!

这到底是怎么回事?任何帮助都非常感谢!我希望在 Ajax 请求后让服务器“推送”很多东西到客户端,但这个问题让这一切变得不可能。

1 个回答

1

可以考虑使用HTML5的WebSockets和Worker API的组合,这样可以在不影响用户界面性能的情况下,异步地从服务器发送和接收数据。

http://dev.w3.org/html5/websockets/

http://net.tutsplus.com/tutorials/javascript-ajax/start-using-html5-websockets-today/(这个教程假设服务器端使用PHP技术)

http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html

另一种选择

a) 在 mousedownkeyup 事件时

- record the cursor position in the text-box - store it in C1.

b) 在 textchange 事件时

> record the cursor position - store it in C2.

> send only the content between C1 and C2 to your server. Also send the values C1 and C2 to the server, i.e your AJAX payload will look something like: 

{ c1: C1, c2: C2, data: <text in the text-box from C1 to C2> }

你需要检查 c1 > c2,并适当地获取子字符串,反之亦然。

这样,每次只会把“变化”的部分发送到服务器,而不是整个文本。不过,如果你复制粘贴了5MB的内容,这样做就没有任何改善。但对于单个字符的变化(比如打字、粘贴小段落等),这种方法应该效果不错。

撰写回答