2011-12-26 52 views
5

Js:Vòng lặp vô hạn PHP hoặc jQuery setInterval?

<script> 
function cometConnect(){ 
    $.ajax({ 
      cache:false, 
      type:"post", 
      data:'ts='+1, 
      url: 'Controller/chatting', 
      async: true, 
      success: function (arr1) { 
       $(".page-header").append(arr1); 
      }, 
      complete:function(){ 
      cometConnect(true); 
      nerr=false; 
      }, 
      dataType: "text" 
     }); 
} 
cometConnect(); 
</script> 

Php:

public function chatting() 
{ 
    while(true) 
    { 
     if(memcache_get(new_message)) 
      return new_message; 
     sleep(0.5); 
    } 
} 

Đây có phải là một giải pháp tốt hơn so với thiết setInterval này kết nối với các phương pháp PHP trả về thông báo nếu có bất kỳ mỗi 1 giây (1 giây tăng 0,25 cứ sau 5 giây chúng ta hãy nói)?

Nếu tôi sử dụng giải pháp đầu tiên, tôi có thể sử dụng giấc ngủ (0,5) nó sẽ cho tôi tin nhắn ngay lập tức, bởi vì vòng lặp php rẻ, phải không?

Vì vậy, giải pháp nào tốt hơn (quan trọng hơn, việc này tốn ít tài nguyên hơn?). Bởi vì sẽ có hàng trăm cuộc trò chuyện như thế này.

Ngoài ra, giải pháp đầu tiên có thể gây ra sự cố không? Hãy nói rằng tôi sẽ tải lại một trang hoặc tôi sẽ ngừng thực hiện mỗi 30 giây vì vậy tôi sẽ không nhận được 502 Bad Gateway.

EDIT: Tôi tin giải pháp thứ hai tốt hơn, vì vậy tôi sẽ triển khai lại trang web của mình, nhưng tôi chỉ tò mò liệu điều này có thể gây ra sự cố cho người dùng hay không? Có thể điều gì đó không mong đợi xảy ra? Vấn đề đầu tiên tôi nhận thấy là bạn không thể truy cập trang khác cho đến khi có ít nhất một thư mới.

Trả lời

9

Trò chuyện là một trong nhiều giao tiếp, trong khi mỗi người trong số nhiều người có thể gửi tin nhắn và sẽ nhận tin nhắn từ mọi người khác.

Hai hành động này (gửi, nhận) xảy ra liên tục. Vì vậy, điều này trông giống như một vòng lặp vô tận trong khi người dùng có thể tham gia (tham gia trò chuyện) và thoát (rời khỏi trò chuyện).

  1. nhập
  2. gửi thông điệp
  3. nhận được thông báo
  4. thoát

Vì vậy, các vòng lặp trông như thế này (pseudo-code) trên các mặt hàng:

while (userInChat) 
{ 
    if (userEnteredMessages) 
    { 
     userSendMessages(userEnteredMessages) 
    } 
    if (chatNewMessages) 
    { 
     displayMessages(chatNewMessages) 
    } 
} 

Như bạn đã lưu ý trong câu hỏi của mình, vấn đề là trong việc triển khai loại trò chuyện cho một trang web.

Để triển khai "vòng lặp" như vậy cho trang web, trước hết bạn phải đối mặt với tình huống mà bạn không muốn có vòng lặp thực sự tại đây. Miễn là người dùng đang trò chuyện, nó sẽ chạy và chạy và chạy. Vì vậy, bạn muốn phân phối việc thực hiện vòng lặp theo thời gian.

Để làm điều này, bạn có thể chuyển đổi nó thành một tập hợp các chức năng sự kiện:

ChatClient 
{ 
    function onEnter() 
    { 
    } 
    function onUserInput(messages) 
    { 
     sendMessages = send(messages) 

     display(sendMessages) 
    } 
    function onReceive(messages) 
    { 
     display(messages) 
    } 
    function onExit() 
    { 
    } 
} 

Đó là bây giờ có thể kích hoạt sự kiện thay vì có một vòng lặp. Chỉ còn lại là việc triển khai để kích hoạt các sự kiện này theo thời gian, nhưng hiện tại điều này không thực sự thú vị vì nó sẽ phụ thuộc vào cách trao đổi dữ liệu trò chuyện thực sự được triển khai.

Luôn có một điểm từ xa mà một ứng dụng trò chuyện (bằng cách nào đó) được kết nối với để gửi tin nhắn của chính nó và nhận tin nhắn mới từ đó.

Đây là một số loại luồng tin nhắn trò chuyện. Một lần nữa điều này trông giống như một vòng lặp, nhưng infact đó là một dòng. Giống như trong vòng lặp của máy khách trò chuyện, tại một thời điểm nào đó nó sẽ nối vào luồng và sẽ gửi đầu vào (ghi) và nhận đầu ra (đọc) từ luồng đó.

Điều này đã được hiển thị trong mã giả ChatClient ở trên, có sự kiện khi người dùng nhập một hoặc nhiều thư mà sau đó sẽ được gửi (văn bản). Và đọc tin nhắn sẽ có sẵn trong chức năng sự kiện onReceive.

Khi luồng là dữ liệu theo thứ tự, cần phải có thứ tự. Vì đây là tất cả sự kiện dựa trên và nhiều khách hàng có sẵn, điều này cần một số xử lý chuyên dụng. Theo thứ tự là tương đối, nó sẽ chỉ hoạt động trong bối cảnh của nó. Ngữ cảnh có thể là thời gian (một tin nhắn xuất hiện trước một tin nhắn khác), nhưng nếu ứng dụng trò chuyện có một đồng hồ khác là máy chủ hoặc máy khách khác, chúng tôi không thể sử dụng đồng hồ hiện tại làm nguồn thời gian cho thứ tự các thông điệp, vì nó thường khác nhau giữa các máy tính trong mạng WAN.

Thay vào đó bạn tạo thời gian của riêng mình để xếp hàng tất cả thư. Với thời gian chia sẻ trên tất cả các máy khách và máy chủ, luồng có thứ tự có thể được triển khai. Điều này có thể dễ dàng thực hiện bằng cách chỉ đánh số tin nhắn ở vị trí trung tâm. May mắn là cuộc trò chuyện của bạn có một vị trí trung tâm, máy chủ.

Luồng tin nhắn bắt đầu bằng tin nhắn đầu tiên và kết thúc bằng tin nhắn cuối cùng. Vì vậy, những gì bạn chỉ cần làm là để cung cấp cho các tin nhắn đầu tiên số 1 và sau đó mỗi tin nhắn mới sẽ nhận được số cao hơn tiếp theo. Hãy gọi nó là ID tin nhắn.

Vì vậy, bất kể bạn sẽ sử dụng công nghệ máy chủ nào, cuộc trò chuyện sẽ biết loại tin nhắn: Tin nhắn có ID và tin nhắn không có ID.Điều này cũng thể hiện trạng thái của tin nhắn: không phải là một phần hoặc một phần của luồng.

Không có thư liên quan đến luồng là thư mà người dùng đã nhập nhưng chưa được gửi đến máy chủ. Trong khi máy chủ nhận được tin nhắn "miễn phí", nó có thể đưa chúng vào luồng bằng cách gán ID:

function onUserInput(messages) 
    { 
     sendMessages = send(messages) 

     display(sendMessages) 
    } 

Như ví dụ mã giả này cho thấy, đây là những gì đang xảy ra ở đây. Sự kiện onUserInput nhận được các tin nhắn chưa phải là một phần của luồng. Thói quen sendMessages sẽ trả về biểu diễn được truyền trực tiếp của chúng, sau đó được hiển thị.

Thói quen hiển thị sau đó có thể hiển thị thông báo trong thứ tự dòng của chúng. Vì vậy, vẫn không phụ thuộc vào cách thực hiện truyền thông máy khách/máy chủ, với cấu trúc như vậy bạn thực sự có thể xử lý một hệ thống trò chuyện dựa trên tin nhắn và tách nó khỏi các công nghệ cơ bản.

Điều duy nhất mà máy chủ cần làm là nhận tin nhắn, cung cấp cho mỗi tin nhắn một ID và trả lại các ID này. Việc gán ID thường được thực hiện khi máy chủ lưu trữ các thông điệp vào cơ sở dữ liệu của nó. Một cơ sở dữ liệu tốt sẽ chú ý đến các thông điệp số đúng cách, vì vậy không có nhiều việc phải làm.

Tương tác khác là đọc thư mới từ máy chủ. Để thực hiện điều này qua mạng một cách hiệu quả, máy khách sẽ thông báo cho máy chủ biết thông điệp nào mà nó thích đọc từ đó. Sau đó, máy chủ sẽ chuyển các tin nhắn từ thời gian đó (ID) đến máy khách.

Như điều này cho thấy, từ vòng lặp "vô tận" trong đầu nó bây giờ biến thành một hệ thống dựa trên sự kiện với các cuộc gọi từ xa. Khi các cuộc gọi từ xa đắt tiền, tốt hơn hết là làm cho chúng có thể chuyển nhiều dữ liệu với một kết nối. Một phần trong số đó đã có trong mã giả vì có thể gửi một hoặc nhiều thư đến máy chủ và nhận được không hoặc nhiều tin nhắn từ máy chủ cùng một lúc.

Việc triển khai lý tưởng sẽ là có một kết nối với máy chủ cho phép đọc và soạn tin nhắn với máy chủ ở chế độ song công. Tuy nhiên, không có công nghệ nào tồn tại trong javascript. Những thứ này đang được phát triển với Websockets và Webstream APIs và tương tự nhưng trong thời điểm này chúng ta hãy xem xét những thứ đơn giản và xem chúng ta có gì: yêu cầu HTTP không trạng thái, một số PHP trên máy chủ và cơ sở dữ liệu MySQL.

Luồng thông báo có thể được biểu diễn trong bảng cơ sở dữ liệu có khóa duy nhất tăng tự động cho ID và các trường khác để lưu trữ thư.

Kịch bản giao dịch ghi sẽ chỉ kết nối với cơ sở dữ liệu, chèn (các) thư và trả lại ID. Đó là một hoạt động rất phổ biến và nó phải được nhanh chóng (mysql có một loại cầu memcache mà nên làm cho hoạt động lưu trữ nhanh hơn và thuận tiện hơn).

Tập lệnh giao dịch đọc đơn giản như nhau, nó sẽ chỉ đọc tất cả các thư có ID cao hơn được truyền cho nó và trả lại cho khách hàng.

Giữ các tập lệnh này càng đơn giản càng tốt và tối ưu hóa thời gian đọc/ghi vào cửa hàng, để chúng có thể thực thi nhanh và bạn hoàn thành ngay cả khi trò chuyện qua HTTP thuần túy.

Máy chủ web của bạn và kết nối internet tổng thể có thể không đủ nhanh (mặc dù có keep-alive).

Tuy nhiên, HTTP phải đủ tốt để thử nghiệm nếu hệ thống trò chuyện của bạn thực sự hoạt động mà không có bất kỳ vòng lặp nào, không phải máy khách, cũng như phía máy chủ.

Nó cũng tốt để giữ các máy chủ chết đơn giản, bởi vì mỗi khách hàng dựa vào họ, vì vậy họ chỉ nên làm công việc của họ và đó là nó.

Bạn có thể bất cứ lúc nào thay đổi máy chủ (hoặc cung cấp loại khác nhau của máy chủ) có thể tương tác với khách hàng trò chuyện của bạn bằng cách đưa ra các chat client triển khai khác nhau của gửi và nhận các chức năng. Ví dụ. Tôi thấy trong câu hỏi của bạn rằng bạn đang sử dụng sao chổi, điều này cũng hoạt động tốt, có thể dễ dàng thực hiện trực tiếp máy chủ cho sao chổi.

Nếu trong WebSockets tương lai có thể truy cập hơn (mà có thể không bao giờ có trường hợp vì cân nhắc an ninh), bạn có thể cung cấp một loại máy chủ cho WebSockets là tốt. Miễn là cấu trúc dữ liệu của luồng là nguyên vẹn, điều này sẽ làm việc với các loại máy chủ khác nhau bên cạnh nhau. Cơ sở dữ liệu sẽ xử lý sự đồng dư.

Hy vọng điều này hữu ích.


Cũng giống như một lưu ý thêm: HTML5 cung cấp một cái gì đó gọi là Stream Updates with Server-Sent Events với một online demoPHP/JS sources. Tính năng HTML 5 cung cấp một đối tượng sự kiện trong javascript có thể được sử dụng để tạo ra một ứng dụng thực hiện giao tác khách hàng trò chuyện mẫu.

+1

+1, đây là câu trả lời duy nhất (cho đến nay) không chỉ đề xuất một cách tiếp cận khác với vòng lặp vô tận, mà còn cung cấp thông tin về cách tạo trao đổi tin nhắn full duplex (hoặc mô phỏng) dựa trên web. –

+1

+1 chỉ vì những người viết này nhiều ?! Ý tôi là, tôi đã đọc các biểu hiện ngắn hơn. Tôi đã có các chuyến đi ngắn hơn đến DMV. Tôi đã có bữa sáng ngắn hơn với cặp song sinh 2 tuổi. Tất cả đùa sang một bên, chi tiết và suy nghĩ tốt đẹp! – iND

2

Trước hết, hãy tự hỏi nếu cần cập nhật trò chuyện thường xuyên. Loại trò chuyện nào sẽ xảy ra? Là thời gian thực? Đơn giản Q & A? Hô trợ ky thuật? Vv Trong tất cả trừ các trường hợp trò chuyện trong thời gian thực, bạn sẽ sử dụng thiết kế dựa trên JS lâu hơn, vì các phản hồi tức thì không quan trọng. Nếu đây là cuộc trò chuyện trong thời gian thực, thì bạn nên xem xét thiết kế giống như Gmail, theo đó bạn giữ một XHR mở và đẩy thư lại cho khách hàng khi họ nhận được. Nếu tài nguyên kết nối là một mối quan tâm, bạn có thể nhận được bằng cách sử dụng bỏ phiếu dài với một khoảng thời gian rất ngắn (ví dụ 5-10 giây).

5

Tôi đã viết một bài đăng blog về cách tôi phải xử lý một vấn đề tương tự (bằng cách sử dụng node.js, nhưng các nguyên tắc áp dụng). http://j-query.blogspot.com/2011/11/strategies-for-scaling-real-time-web.html

Đề xuất của tôi là nếu bạn cần bộ nhớ cache như điên trên lớp máy chủ web, điều này có nghĩa là cuộc gọi AJAX của bạn cần có dấu thời gian hoặc b) socket.io, được xây dựng để mở rộng các ứng dụng web theo thời gian thực và có hỗ trợ tích hợp cho các kênh.

5

Vòng lặp vô hạn trong php có thể và sẽ sử dụng 100% CPU của bạn. Chức năng ngủ sẽ khắc phục vấn đề đó. Tuy nhiên, có thể bạn không muốn có một quy trình HTTP riêng biệt chạy mọi lúc cho mọi máy khách được kết nối với máy chủ của bạn vì bạn sẽ hết các kết nối. Bạn chỉ có thể có một quá trình php xem tất cả các thư gửi đến và định tuyến chúng đến đúng người khi chúng đến. Quá trình này có thể được khởi chạy từ một công việc cron một lần một phút. Tôi đã viết loại điều này nhiều lần và nó hoạt động như một sự quyến rũ. Lưu ý: Đảm bảo rằng bạn không chạy quy trình nếu nó đang chạy hoặc bạn sẽ gặp phải sự cố đa xử lý (như nhận được thư kép). Nói cách khác, bạn cần phải làm cho quy trình xử lý an toàn.

Nếu bạn muốn trò chuyện trong thời gian thực, bạn có thể muốn xem StreamHub mở kết nối hai chiều đầy đủ tới trình duyệt của khách hàng.

+0

Đây là câu trả lời đúng nếu bạn nhấn mạnh vào việc sử dụng PHP. Tuy nhiên, PHP không được thiết kế để trở thành một máy chủ trò chuyện nên bạn nên xem xét các giải pháp khác như Node.js. PHP là tuyệt vời để làm các trang web tuy nhiên. –

5

Nó không phải là một PHP hoặc jQuery nhiệm vụ bây giờ. Node.js! Có socket.io, có nghĩa là WebSockets.

Tôi sẽ giải thích lý do tại sao Node.js là tốt hơn. Tôi có một nhiệm vụ để làm mới đánh dấu trên trang mỗi, ví dụ, 10 giây. Tôi đã thực hiện nó với phương pháp đầu tiên. Khi người dùng liên tục đếm đến 200. Http server và php gặp rắc rối. Có rất nhiều yêu cầu không liên tục.

Whats cung cấp cho bạn Node.js:

  • Tạo phòng riêng biệt để chat (here)
  • Gửi dữ liệu, chỉ dành cho những ai có bản cập nhật (ví dụ, nếu tôi không có bất kỳ tin nhắn mới của tôi làm mới sẽ bị chặn khi sẽ có lựa chọn từ cơ sở dữ liệu)
  • Bạn chạy 1 truy vấn để DB mỗi 0,5 giây, bất kể có bao nhiêu người dùng có

Chỉ cần nhìn vào Node.j s và Socket.io. Giải pháp này giúp tôi với một sự thúc đẩy tuyệt vời.

Các vấn đề liên quan