Strategi terbaik untuk melaporkan kemajuan ke UI - bagaimana seharusnya panggilan balik itu terjadi?

11

Kadang-kadang pengguna memulai operasi teknis tambahan yang membutuhkan waktu untuk dijalankan. Dalam kasus ini, biasanya baik untuk menampilkan semacam progress bar, bersama dengan informasi tentang tugas yang sedang dijalankan saat ini.

Untuk menghindari kopling erat antara UI dan lapisan logika, biasanya yang terbaik adalah membuat komunikasi terjadi melalui beberapa jenis proxy. Artinya, back-end tidak boleh memanipulasi elemen UI sendiri, atau bahkan berinteraksi dengan lapisan perantara secara langsung.

Jelas, harus ada beberapa panggilan balik di suatu tempat untuk membuat pekerjaan ini. Saya biasanya menerapkannya dalam satu dari dua cara:

  1. Berikan objek yang dapat diubah ke back-end, dan mintalah back-end untuk mengubahnya pada progres. Objek memberi tahu front-end ketika perubahan terjadi.

  2. Lewati fungsi panggil balik formulir void f(ProgressObject)atau ProgressObject -> unityang dipanggil kembali . Dalam hal ini, back-end membangun ProgressObjectdan itu benar-benar pasif. Saya pikir itu harus membangun objek baru setiap kali ingin melaporkan kemajuan.

Apa kekurangan dan kelebihan dari metode ini? Apakah ada metode terbaik yang disepakati untuk digunakan? Apakah ada keadaan yang berbeda untuk penggunaannya?

Apakah ada teknik pelaporan kemajuan yang sama sekali berbeda yang saya abaikan?

GregRos
sumber
1
Mengenai mutable vs immutable, kelebihan dan kekurangannya sama seperti di tempat lain. Mengenai objek kemajuan, ini bisa sangat ringan; bisa sesederhana angka tunggal: persentase.
Robert Harvey
@RobertHarvey Ukuran objek kemajuan biasanya tergantung pada persyaratan UI. Lihatlah dialog copy Windows misalnya. Saya membayangkan itu membutuhkan banyak informasi.
GregRos
1
@RobertHarvey Itu berita baru bagi saya. Apa itu?
GregRos
1
Saya akan gigit. Kami menggunakan BackgroundWorkerRH itu menyebutkan. Dibungkus dalam kelas khusus bersama dengan "formulir kemajuan", dll. Dan mekanisme sederhana untuk mengkomunikasikan pengecualian - sebagaimana BackgroundWorkerdesain berjalan di utas terpisah. Sejauh kita menggunakan fitur-fiturnya dengan cara yang disarankan oleh .Net maka itu bisa dikatakan idiomatis. Dan dalam konteks bahasa / kerangka kerja tertentu "idiomatik" mungkin yang terbaik.
radarbob
2
Saya tidak melihat perbedaan signifikan antara kedua metode Anda. Objek yang diteruskan dari ujung depan ke ujung yang menawarkan metode yang mengarah ke pemberitahuan ujung depan sebenarnya memiliki fungsi callback. Dan jika pendekatan kedua Anda menggunakan objek parameter yang lebih atau kurang kompleks untuk menyampaikan informasi, atau jika menggunakan beberapa nilai sederhana tidak membuat perbedaan dari sudut pandang arsitektur. Dalam kedua pendekatan tersebut backend secara aktif menginformasikan frontend, perbedaannya hanyalah detail kecil, sehingga tidak ada konsep berbeda yang dijelaskan di sini.
Doc Brown

Jawaban:

8

Berikan objek yang dapat diubah ke back-end, dan mintalah back-end untuk mengubahnya pada progres. Objek memberi tahu front-end ketika perubahan terjadi.

Sulit untuk menyeimbangkan efisiensi jika backend memberi tahu dalam hal ini. Tanpa peduli Anda mungkin menemukan bahwa peningkatan kemajuan Anda berakhir dengan menggandakan atau tiga kali lipat waktu yang dibutuhkan untuk menyelesaikan operasi jika Anda bertujuan untuk pembaruan kemajuan yang sangat lancar.

Lewati fungsi panggilan balik dari form void f (ProgressObject) atau ProgressObject -> unit yang dipanggil oleh back-end. Dalam hal ini, back-end membangun ProgressObject dan itu sepenuhnya pasif. Saya pikir itu harus membangun objek baru setiap kali ingin melaporkan kemajuan.

Saya tidak mendapatkan perbedaan di sini begitu banyak.

Apakah ada teknik pelaporan kemajuan yang sama sekali berbeda yang saya abaikan?

Polling dari front-end di utas terpisah dengan penambahan atom di backend. Polling masuk akal di sini karena ini untuk operasi yang selesai dalam periode yang terbatas dan kemungkinan ujung mengambil perubahan negara tinggi, terutama jika Anda bertujuan untuk progress bar halus seperti sutra. Anda dapat mempertimbangkan variabel kondisi jika Anda tidak menyukai gagasan polling dari thread frontend, tetapi dalam hal ini Anda mungkin ingin menghindari memberi tahu setiap kenaikan progress bar granular tunggal.


sumber
2

Inilah perbedaan antara mekanisme pemberitahuan push dan pull .

Objek yang dapat diubah ( tarikan ) perlu disurvei berulang kali oleh UI dan disinkronkan jika Anda mengharapkan tugas back-end akan dieksekusi di latar belakang / utas pekerja.

Callback ( push ) hanya akan membuat UI berfungsi ketika ada sesuatu yang benar-benar berubah. Banyak kerangka kerja UI juga memiliki invokeOnUIThread callable dari utas pekerja untuk membuat sepotong kode dijalankan pada utas UI sehingga Anda benar-benar dapat membuat perubahan tanpa menginjak bahaya yang terkait dengan utas. (pun intended)

Secara umum pemberitahuan push lebih disukai karena mereka hanya membuat pekerjaan ketika pekerjaan perlu dilakukan.

aneh ratchet
sumber
1
Saya pikir apa yang Anda katakan benar secara umum. Namun, untuk kasus khusus ini, bilah kemajuan, perubahan dapat terjadi dengan cepat. Jika harapan Anda adalah bahwa "kemajuan" cenderung berubah beberapa kali per detik, lebih masuk akal untuk menggunakan model tarikan karena jika tidak Anda harus khawatir tentang UI yang menerima terlalu banyak pemberitahuan untuk ditangani.
Gort the Robot
Mengirim objek progres dapat mengaburkan mekanisme notifikasi yang Anda gunakan dari back-end, karena mungkin objek progres melakukan panggilan balik. Sebenarnya saya tidak pernah menggunakan mekanisme tarikan sejauh yang saya ingat, dan saya agak lupa tentang hal itu: 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.- Tidak jika objek yang dapat diubah adalah dialog itu sendiri, atau antarmuka yang berfungsi untuk itu. Tentu saja, itu sama dengan panggilan balik.
Robert Harvey
1
Hah? OP dengan jelas menggambarkan dua bentuk mekanisme push yang berbeda, karena tidak ada satupun polling yang diperlukan.
Doc Brown
0

Saya menggunakan soket web dengan AngularJS. Ketika ujung depan menerima pesan, itu menampilkannya di area pesan yang ditunjuk yang memudar menjadi kosong setelah beberapa detik. Di bagian belakang saya hanya memposting pesan status ke antrian pesan. Saya hanya mengirim teks, tetapi tidak ada alasan saya tidak bisa mengirim objek status dengan nilai-nilai seperti persentase selesai atau kecepatan transfer.

TMN
sumber
0

Anda menyebutkan "dua cara" Anda seolah-olah itu adalah konsep yang terpisah tetapi saya ingin sedikit mendorongnya.

  1. Berikan objek yang dapat diubah ke back-end, dan mintalah back-end untuk mengubahnya pada progres. Objek memberi tahu front-end ketika perubahan terjadi.

Anda telah mengatakan bahwa Anda ingin menghindari kopling-dekat UI dan logika, jadi saya dapat dengan aman berasumsi bahwa "objek yang dapat diubah" yang Anda lewati ini sebenarnya adalah implementasi dari antarmuka tertentu yang didefinisikan dalam modul logika. Dengan demikian, ini hanyalah cara lain untuk mengirimkan panggilan balik ke proses yang secara berkala disebut dengan informasi tentang kemajuan.

Adapun manfaat dan kelemahan ...

Kelemahan untuk metode (1) adalah kelas yang mengimplementasikan antarmuka hanya dapat melakukannya sekali. (Jika Anda ingin melakukan pekerjaan yang berbeda dengan doa yang berbeda, Anda akan memerlukan pernyataan pergantian atau pola pengunjung.) Dengan metode (2), objek yang sama dapat menggunakan panggilan balik yang berbeda untuk setiap doa kode backend tanpa memerlukan beralih.

Kekuatan untuk metode (1) adalah bahwa jauh lebih mudah untuk memiliki beberapa metode pada antarmuka daripada berurusan dengan beberapa metode callback (2) atau panggilan balik tunggal dengan pernyataan switch untuk beberapa konteks.

Daniel T.
sumber
-2

Teknik yang dapat Anda gunakan mungkin sangat sulit.

Saya mencoba mencari tahu dengan skenario yang berbeda

  • Permintaan ke db
  • Unduh berkas

Permintaan login sederhana ke db (berarti merespons dari db dengan satu elemt) tidak memerlukan laporan kemajuan tetapi selalu dapat mengaktifkan utas UI di tugas yang berbeda ex. async atau backgroundworker, di sini Anda hanya perlu satu panggilan balik untuk hasil.

Tetapi bagaimana jika Anda meminta untuk melihat semua inventaris Anda dengan item 1mln? Query ini harus selesai beberapa menit, jadi dalam hal ini Anda perlu mengimplementasikan kemajuan perport Anda dalam logika bisnis Anda dalam item form / item, maka Anda dapat memperbarui UI Anda dan dapat diberikan opsi untuk membatalkan panggilan balik.

Kasus yang sama untuk pengunduhan file. Anda selalu dapat menerapkan di sini panggilan balik kemajuan Anda dalam bentuk byte byte, dan menahan semua kontrol komunikasi melalui http adalah pola yang sangat umum.

Pada pendekatan pribadi saya, saya menerapkan logika kemajuan bisnis saya hanya untuk klien saya, menghindari untuk berbagi objek lain dengan titik akhir.

Marco Luongo
sumber
1
Ini tidak benar-benar menjawab pertanyaan tentang kelebihan / kekurangan.
Benni