Chiến lược tốt nhất để báo cáo tiến trình tới UI - cuộc gọi lại nên diễn ra như thế nào?


11

Đôi khi người dùng bắt đầu một hoạt động kỹ thuật mở rộng phải mất một thời gian để thực hiện. Trong những trường hợp này, thường là tốt để hiển thị một số loại thanh tiến trình, cùng với thông tin về nhiệm vụ nào đang được thực hiện ngay bây giờ.

Để tránh kết hợp chặt chẽ giữa UI và các lớp logic, thông thường tốt nhất là có giao tiếp xảy ra thông qua một số loại proxy. Đó là, back-end không nên thao túng các thành phần UI của chính nó, hoặc thậm chí tương tác trực tiếp với lớp trung gian.

Rõ ràng, phải có một số cuộc gọi lại ở đâu đó để thực hiện công việc này. Tôi thường thực hiện nó theo một trong hai cách:

  1. Truyền một đối tượng có thể thay đổi vào back-end và để back-end thực hiện các thay đổi đối với tiến trình đó. Đối tượng thông báo cho giao diện người dùng khi có thay đổi.

  2. Vượt qua chức năng gọi lại của biểu mẫu void f(ProgressObject)hoặc ProgressObject -> unityêu cầu back-end. Trong trường hợp này, back-end xây dựng ProgressObjectvà nó hoàn toàn thụ động. Nó phải xây dựng một đối tượng mới mỗi lần nó muốn báo cáo tiến độ, tôi giả sử.

Hạn chế và ưu điểm của các phương pháp này là gì? Có một phương pháp tốt nhất để sử dụng? Có những trường hợp khác nhau cho việc sử dụng của họ?

Có các kỹ thuật báo cáo tiến độ hoàn toàn khác nhau mà tôi đã bỏ qua không?


1
Về khả năng biến đổi và bất biến, những ưu điểm và nhược điểm cũng giống như bất kỳ nơi nào khác. Về đối tượng tiến độ, điều này có thể rất nhẹ; nó có thể đơn giản như một con số duy nhất: một tỷ lệ phần trăm.
Robert Harvey

@RobertHarvey Kích thước của đối tượng tiến trình thường phụ thuộc vào yêu cầu UI. Nhìn vào hộp thoại sao chép Windows chẳng hạn. Tôi tưởng tượng nó đòi hỏi rất nhiều thông tin.
GregRos

1
@RobertHarvey Đó là tin tức với tôi. Nó là gì?
GregRos

1
Tôi sẽ cắn. Chúng tôi sử dụng BackgroundWorkerđề cập đó. Được bao bọc trong một lớp tùy chỉnh cùng với "biểu mẫu tiến trình", v.v. và một cơ chế đơn giản để truyền đạt một ngoại lệ - như BackgroundWorkerthiết kế chạy trong một luồng riêng biệt. Trong phạm vi chúng tôi sử dụng các tính năng của nó theo cách được đề xuất bởi .Net thì có thể nói đó là thành ngữ. Và trong bất kỳ bối cảnh ngôn ngữ / khung cụ thể nào, "thành ngữ" có thể là tốt nhất.
radarbob

2
Tôi không thấy bất kỳ sự khác biệt đáng kể giữa hai phương pháp của bạn. Một đối tượng được truyền từ giao diện người dùng đến phụ trợ cung cấp các phương thức dẫn đến thông báo về giao diện người dùng thực sự có chức năng gọi lại. Và nếu cách tiếp cận thứ hai của bạn sử dụng một đối tượng tham số phức tạp hơn hoặc ít hơn để truyền thông tin hoặc nếu nó sử dụng một vài giá trị đơn giản sẽ không tạo ra sự khác biệt từ quan điểm kiến ​​trúc. Trong cả hai cách tiếp cận, phần phụ trợ chủ động thông báo cho frontend, sự khác biệt chỉ là chi tiết nhỏ, vì vậy không có khái niệm khác được mô tả ở đây.
Doc Brown

Câu trả lời:


8

Truyền một đối tượng có thể thay đổi vào back-end và để back-end thực hiện các thay đổi đối với tiến trình đó. Đối tượng thông báo cho giao diện người dùng khi có thay đổi.

Thật khó để cân bằng hiệu quả nếu phần phụ trợ thông báo về mặt này. Nếu không quan tâm, bạn có thể thấy rằng việc tăng tiến độ của bạn sẽ tăng gấp đôi hoặc gấp ba thời gian cần thiết để hoàn thành thao tác nếu bạn đang nhắm đến một bản cập nhật tiến độ rất suôn sẻ.

Truyền một hàm gọi lại có dạng void f (ProgressObject) hoặc ProgressObject -> đơn vị mà back-end gọi. Trong trường hợp này, back-end xây dựng ProgressObject và nó hoàn toàn thụ động. Nó phải xây dựng một đối tượng mới mỗi lần nó muốn báo cáo tiến độ, tôi giả sử.

Tôi không nhận được sự khác biệt ở đây rất nhiều.

Có các kỹ thuật báo cáo tiến độ hoàn toàn khác nhau mà tôi đã bỏ qua không?

Thăm dò ý kiến ​​từ mặt trước trong một luồng riêng biệt với gia số nguyên tử trong phần phụ trợ. Bỏ phiếu có ý nghĩa ở đây vì đây là một hoạt động kết thúc trong một khoảng thời gian hữu hạn và khả năng giao diện nhận thay đổi trạng thái là rất cao, đặc biệt là nếu bạn đang nhắm đến một thanh tiến trình mượt mà. Bạn có thể xem xét các biến điều kiện nếu bạn không thích ý tưởng bỏ phiếu từ luồng frontend, nhưng trong trường hợp đó bạn có thể muốn tránh thông báo về mỗi lần tăng thanh tiến trình chi tiết đơn lẻ.


2

Đây là sự khác biệt giữa cơ chế thông báo đẩykéo .

Đối tượng có thể thay đổi ( kéo ) sẽ cần được thăm dò lặp lại bởi UI và được đồng bộ hóa nếu bạn mong muốn tác vụ back-end được thực thi trong luồng xử lý nền / worker.

Cuộc gọi lại ( đẩy ) sẽ chỉ tạo ra công việc cho UI khi có gì đó thực sự thay đổi. Nhiều khung công tác UI cũng có một hàm invokeOnUIThread có thể gọi được từ một luồng công nhân để tạo một đoạn mã chạy trên luồng UI để bạn thực sự có thể thực hiện các thay đổi mà không gặp phải các mối nguy liên quan đến luồng. (ý định chơi chữ)

Nói chung, thông báo đẩy được ưa thích hơn vì chúng chỉ thực hiện công việc khi cần hoàn thành công việc.


1
Tôi nghĩ những gì bạn nói là đúng nói chung. Tuy nhiên, đối với trường hợp cụ thể này, một thanh tiến trình, những thay đổi có thể xảy ra nhanh chóng. Nếu kỳ vọng của bạn là "tiến trình" có thể thay đổi nhiều lần trong một giây, thì sẽ tốt hơn nếu sử dụng mô hình kéo vì nếu không bạn phải lo lắng về việc UI có quá nhiều thông báo để xử lý.
Gort Robot

Gửi một đối tượng tiến trình có thể che khuất cơ chế thông báo mà bạn đang sử dụng từ phía sau, vì có thể đối tượng tiến trình đang thực hiện các cuộc gọi lại. Tôi thực sự chưa bao giờ sử dụng một cơ chế kéo theo như tôi nhớ, và tôi đã quên mất nó: P
GregRos

The mutable object (the pull) will need to be repeatably polled by the UI and synchronized if you expect the back-end task to be executed in a background/worker thread.- Không phải nếu đối tượng có thể thay đổi là chính hộp thoại hoặc giao diện làm việc với nó. Tất nhiên, dù sao thì đó cũng là một cuộc gọi lại.
Robert Harvey

1
Huh? OP mô tả rõ ràng hai hình thức khác nhau của cơ chế đẩy, trong đó không phải là một cuộc bỏ phiếu cần thiết.
Doc Brown

0

Tôi đang sử dụng websockets với AngularJS. Khi giao diện người dùng nhận được tin nhắn, nó sẽ hiển thị nó trong vùng tin nhắn được chỉ định sẽ mờ dần sau vài giây. Ở mặt sau, tôi chỉ đăng thông điệp trạng thái vào hàng đợi tin nhắn. Tôi chỉ gửi văn bản, nhưng không có lý do gì tôi không thể gửi một đối tượng trạng thái với các giá trị như hoàn thành phần trăm hoặc tốc độ truyền.


0

Bạn đề cập đến "hai cách" của bạn như thể chúng là những khái niệm riêng biệt nhưng tôi muốn đẩy lùi điều đó một chút.

  1. Truyền một đối tượng có thể thay đổi vào back-end và để back-end thực hiện các thay đổi đối với tiến trình đó. Đối tượng thông báo cho giao diện người dùng khi có thay đổi.

Bạn đã nói rằng bạn muốn tránh giao diện người dùng và logic kết hợp chặt chẽ, vì vậy tôi có thể giả định rằng "đối tượng có thể thay đổi" này mà bạn đang truyền thực sự là một triển khai của một giao diện cụ thể được xác định trong mô-đun logic. Như vậy, đây chỉ là một cách khác để chuyển một cuộc gọi lại vào quy trình đó là các cuộc gọi định kỳ với thông tin về tiến trình.

Về lợi ích và nhược điểm ...

Một nhược điểm của phương thức (1) là lớp thực hiện giao diện chỉ có thể thực hiện một lần. (Nếu bạn muốn thực hiện các công việc khác nhau với các yêu cầu khác nhau, bạn sẽ cần một câu lệnh chuyển đổi hoặc mẫu khách truy cập.) Với phương thức (2), cùng một đối tượng có thể sử dụng một cuộc gọi lại khác nhau cho mỗi lần gọi mã phụ trợ mà không cần phải có công tắc điện.

Một điểm mạnh của phương thức (1) là có nhiều phương thức trên giao diện dễ dàng hơn nhiều so với xử lý nhiều cuộc gọi lại của phương thức (2) hoặc cuộc gọi lại đơn lẻ với một câu lệnh chuyển đổi cho nhiều ngữ cảnh.


-2

Các kỹ thuật bạn có thể sử dụng có thể rất khác nhau.

Tôi cố gắng tìm ra kịch bản khác

  • Yêu cầu db
  • Tải tập tin

Một yêu cầu đăng nhập đơn giản tới db (có nghĩa là phản hồi từ db với một elemt) không cần tiến trình báo cáo nhưng nó có thể loại bỏ luồng UI trong nhiệm vụ riêng biệt. async hoặc backgroundworker, ở đây bạn chỉ cần một cuộc gọi lại cho kết quả.

Nhưng nếu bạn truy vấn để xem tất cả hàng tồn kho của bạn với mục 1mln thì sao? Truy vấn này sẽ mất vài phút để hoàn thành, vì vậy trong trường hợp này, bạn cần triển khai tiến trình perport trong logic nghiệp vụ của mình trong mục / mục biểu mẫu, sau đó bạn có thể cập nhật giao diện người dùng của mình và có thể đưa ra tùy chọn hủy cuộc gọi lại.

Trường hợp tương tự để tải tập tin. Bạn luôn có thể thực hiện ở đây cuộc gọi lại tiến trình của mình dưới dạng byte byte và giữ tất cả các điều khiển kết hợp trên http là mẫu rất phổ biến.

Theo cách tiếp cận cá nhân của tôi, tôi chỉ triển khai logic tiến trình kinh doanh của mình cho khách hàng, tránh chia sẻ đối tượng khác với điểm cuối.


1
Điều này không thực sự trả lời câu hỏi về ưu điểm / nhược điểm.
Benni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.