Neden “geri arama işlevlerine” ihtiyacımız var?


16

Kitabı okuyorum programming in Lua. Dedi ki

Kapaklar birçok bağlamda değerli bir araç sağlar. Gördüğümüz gibi, bunlar sıralama gibi üst düzey işlevlerin argümanları olarak yararlıdır. Kapaklar, newCounter örneğimiz gibi diğer işlevleri de oluşturan işlevler için değerlidir; bu mekanizma, Lua programlarının fonksiyonel dünyadan gelişmiş programlama tekniklerini kullanmasını sağlar. Kapaklar geri arama işlevleri için de yararlıdır. Burada tipik bir örnek, geleneksel bir GUI araç setinde düğmeler oluşturduğunuzda ortaya çıkar. Her düğmede, kullanıcı düğmeye bastığında çağrılacak bir geri arama işlevi vardır; farklı düğmelere basıldığında biraz farklı şeyler yapmasını istiyorsunuz. Örneğin, bir dijital hesap makinesinin her basamak için bir tane olmak üzere on benzer düğmeye ihtiyacı vardır. Her birini aşağıdaki gibi bir işlevle oluşturabilirsiniz:

function digitButton (digit)
  return Button{label = tostring(digit),
                action = function ()
                  add_to_display(digit)
                  end}
end

Ararsam görünüyor digitButton, bu dönecektir actionbu yüzden, ben erişebilir, (bu bir kapatma yaratacaktır) digitgeçirilir digitButton.

Sorum şu:

Why we need call back functions? what situations can I apply this to?


Yazar dedi ki:

Bu örnekte, Button'ın yeni düğmeler oluşturan bir araç takımı işlevi olduğunu varsayıyoruz; etiket düğme etiketidir; ve eylem, düğmeye basıldığında çağrılacak geri arama kapanışıdır. Geri arama, digitButton görevini yaptıktan ve yerel değişken basamak kapsam dışına çıktıktan uzun bir süre sonra çağrılabilir, ancak yine de bu değişkene erişebilir.

yazara göre, benzer bir örnek şöyle düşünüyorum:

function Button(t)
  -- maybe you should set the button here
  return t.action -- so that you can call this later
end

function add_to_display(digit)
  print ("Display the button label: " .. tostring(digit))
end

function digitButton(digit)
  return Button{label = tostring(digit),
                action = function ()
                           add_to_display(digit)
                           end}
end

click_action = digitButton(10)
click_action()

Böylece, the callback can be called a long time after digitButton did its task and after the local variable digit went out of scope.


Yanıtlar:


45

Guy 1 to Guy 2: hey ahbap Bir kullanıcı oraya tıkladığında bir şey yapmak istiyorum, bu iyi olduğunda beni geri ara?

Guy 2, bir kullanıcı buraya tıkladığında Guy 1'i geri çağırır.


1
Bu geri arama şakasını çok beğendim :-P
Lucas Li

6
Sadece ben mi? Bunun neden geri arama işlevlerine ihtiyaç duyduğumuzu nasıl açıkladığını anlamıyorum.
phant0m

2
Daha çok Guy 1, Guy 2'ye "tam zamanı geldiğinde" diyor. Guy 2, gününü anlatıyor ve doğru zamanda bunu yapıyor. Guy 1'i Guy 2'nin arayanı demek istediyseniz, Guy 2 Guy 1'i geri aramadığı için bu yanlıştır, yapılacak şeyi çağırır. Aslında Guy 1, Guy 2'nin arayanıysa, bu senaryoda ellerinizde zor bir döngü olur. Guy 1'in geri arama olmasını istediyseniz, geri arama Guy 2'nin kim olduğu hakkında hiçbir fikri olmadığı ve kesinlikle onu aramasını istemediği için bu yanlıştır.
rism

Bu korkunç bir açıklama.
insidesin

21

Hayır, eylemi asla geri döndürmez . Kullanıcı tıklattığında düğme yürütülür . Ve cevap bu. Kontrol etmediğiniz bir olaya tepki olarak başka bir bileşende gerçekleşmesi gereken eylemleri tanımlamak istediğinizde geri arama işlevlerine ihtiyacınız vardır (sistemin bir parçası olan olay döngüsü, yürütecek olan düğmenin bir yöntemini yürütecektir eylem).


Sana katılmıyorum. Yazımı düzenledim ve bazı kodlar ekledim. Hala eylemin anında gerçekleşmediğini düşünüyorum.
Lucas Li

2
Tim, haklısın - ama Ocak da "Anında değil, kullanıcı üzerine tıkladığında düğme onu çalıştırır".
AlexanderBrevig

@AlexanderBrevig evet, sanırım Jan'ın cevabı benim için çok yararlı. Neyin geri aradığını ve neden geri aramamız gerektiğini bilmeme izin veriyor.
Lucas Li

Geri arama yalnızca birisinin ikinci bir işleve ilk tetiklendiğinde çalışan ve belki de bir ölçütlere dayalı olarak eklenen kirli bir addır. Fonksiyonunuzu well_done () olarak adlandırın ve fark olmaz. Geri arama Doğrulamak gibidir, doğrulamak genellikle iki mesajdan oluşan bir sıradır ve geri arama genellikle iki taneden oluşan bir işlev güvencesidir. 3'ten fazla geri arama zinciri oluşturduysanız, tebrikler, işleri zor yoldan yapmak istersiniz.
m3nda

16

Ben geri arama kullanımı için daha iyi bir örnek asenkron işlevlerde olduğunu düşünüyorum. Lua için konuşamıyorum, ancak JavaScript'te en yaygın asenkron eylemlerden biri AJAX aracılığıyla bir sunucuya başvurmaktır.

AJAX çağrısı eşzamansızdır, yani böyle bir şey yaparsanız:

var ajax = ajaxCall();
if(ajax == true) {
  // Do something
}

ifbloğun içeriği güvenilir bir şekilde çalışmaz ve çalıştığında, bunun nedeni yalnızca ajaxCall(), yürütme ififadeye ulaşmadan önce işlevin bitmesi olmuştur .

Ancak, geri çağrılar, gerekli işlevi çağırmadan önce eşzamansız çağrının tamamlanmasını sağlayarak bu sorunu ortadan kaldırır. Yani, kodunuz böyle bir şeye dönüşür:

function ajaxCallback(response) {   
  if(response == true) {
    // Do something   
  }
}

ajaxCall(ajaxCallback);

Bunun amacı, arayüz çizmek gibi başka şeylere müdahale etmeden veri toplamak gibi şeyleri yapmanıza izin vermektir. Veri toplama senkronize olsaydı, uygulama verileri almak için bekledikçe arayüz yanıt vermezdi. Yanıt vermeyen bir arayüz kullanıcı deneyimi için çok kötüdür, çünkü çoğu kullanıcı uygulamanın "çöktüğünü" düşünecek ve işlemi sonlandırmaya çalışacaktır.

Bunu çalışırken görmek için, tüm sayfayı yeniden yüklemeden herhangi bir güncelleme yapan herhangi bir web sitesine bakmanız yeterlidir. Twitter, LinkedIn ve StackExchange siteleri iyi örneklerdir. Twitter'ın yayınlarda "sonsuz kaydırılması" ve SE'nin bildirimleri (hem kullanıcı bildirimleri hem de bir sorunun yeni etkinliği olan bildirimler için), eşzamansız çağrılar tarafından desteklenir. Bir yerde bir döndürücü gördüğünüzde, bu bölüm eşzamansız bir çağrı yaptı demektir ve bu çağrının bitmesini bekler, ancak arabirimdeki diğer şeylerle etkileşime girebilir (hatta diğer eşzamansız çağrılar yapabilirsiniz). Bu çağrı bittiğinde, arayüz buna göre tepki verir ve güncellenir.


12

Soruyu sordun

Neden "geri arama fonksiyonlarına" ihtiyacımız var?

Kısa ve net bir şekilde cevaplamaya çalışacağım (eğer başarısız olursa, lütfen bu cevabın altındaki wiki bağlantısına bakın).

Geri aramalar, bir şeyin özel uygulanmasını mümkün olan en son ana kadar ertelemek için kullanılır.

Düğme örneği bunun iyi bir örneğidir. Uygulamanızda, yazıcıya bir sayfa basan bir düğme olmasını istediğinizi varsayalım, bunu yapmak için tüm yeni bir PrinterButtonsınıfı kodlamanız gereken bir dünya hayal edebiliyoruz .

Neyse ki, geri aramalar kavramına sahibiz (kalıtım ve şablon deseninin kullanımı da bir tür geri arama anlambilimidir), bu yüzden bunu yapmamız gerekmez.

Bir düğmenin her yönünü yeniden uygulamak yerine, yaptığımız şey düğmenin uygulanmasına eklemektir. ButtonYapmanın konsepte sahip bir şeyi basılı ne zaman. Sadece bir şeyin ne olduğunu söyleriz.

Çerçevelere davranış enjekte etme mekanizmasına geri çağrı denir.

Misal:

Bir HTML düğmesine bazı davranışlar ekleyelim:

<button onclick="print()">Print page through a callback to the print() method</button>

Bu örnekte, onclickbu örnek için print()yöntem olan bir geri aramayı gösterir .


http://en.wikipedia.org/wiki/Callback_(computer_programming)


Teşekkürler, resminizi okuduktan sonra, örnekleri sadece senkronize geri aramalar olan wiki'yi okuyorum.
Lucas Li

bir işleve her problemi olduğunda cevabı söyleyin ve problemleri dinlemek zorundasınız; kendi kendine hallettiği bir problemi çözmek için bir fonksiyon öğretmek.
Joe

8

Neden geri arama fonksiyonlarına ihtiyacımız var? bunu hangi durumlara uygulayabilirim?

Geri arama işlevleri, olay güdümlü programlamada çok kullanışlıdır. Programınızı, olaylar doğru kodu tetikleyecek şekilde ayarlamanıza olanak tanır. Kullanıcıların arayüzdeki herhangi bir öğeyi (düğmeler veya menü öğeleri gibi) tıklayabileceği ve uygun kodun çalıştırılacağı GUI'leri olan programlarda bu çok yaygındır.


1
+ Bu geri aramalar için iyidir, ama onları yazmaktan nefret ediyorum :-)
Mike Dunlavey

Sadece birinci sınıftayken, öğretmenim bize MFC'de nasıl programlanacağımızı öğretti, ama bize geri aramanın ne olduğunu asla söylemedi :-(
Lucas Li

2

Geri aramalar olmadan ne olur:

1. Adam: Tamam, o şeyin olmasını bekliyorum. (ıslık çalıyor, baş parmakları çeviriyor)

2. Adam: Lanet olsun! Guy 1 bana neden bir şey göstermiyor? Bir şeylerin olmasını görmek istiyorum !! Eşyalarım nerede? Burada nasıl bir şeylerin yapılması gerekiyor?


1

Firstoff, geri arama terimi, bir şey için kullanılan bir kapatma anlamına gelir.

Örneğin, bir kapatma işlevi oluşturduğunuzu ve yalnızca bir değişkende sakladığınızı varsayalım. Bu bir geri arama değildir, çünkü hiçbir şey için kullanılmaz.

Ancak, bir kapak oluşturduğunuzu ve bir şey olduğunda çağrılacak bir yerde sakladığınızı varsayalım. Artık geri arama olarak adlandırılıyor.

Genellikle, geri çağrılar, programın kendisini çağıran bölümlerden farklı bölümleri tarafından oluşturulur. Bu nedenle, programın bazı bölümlerinin diğer bölümlerini "geri çağırdığını" hayal etmek kolaydır.

Basitçe söylemek gerekirse, geri aramalar, programın bir bölümünün başka bir bölüme bir şey olduğunda bir şey yapmasını söylemesine izin verir.

Bir kapanışta kullanılmasından dolayı değişkenlerin canlı tutulması ise, bu, yükselmeler (Lua bilmeyenlerde "yerel değişkenlerin ömrünü uzatmak" olarak adlandırılan) tamamen farklı bir özelliktir. Ve bu da oldukça faydalı.


evet, Extending the lifetime of local variablesaynı zamanda terim demek upvalue.
Lucas Li

Hmm, ilginç. Hızlı bir Google araması, zaman zaman diğer dilleri tanımlamak için kullanıldığını göstermesine rağmen, yükselme terimi Lua'ya özgü görünmektedir. Cevabıma ekleyeceğim.
Jonathan Graef

1

En azından Fortran'ın ilk günlerinden beri geri aramalar yapıldı. Örneğin, Runge-Kutta çözücü gibi bir ODE (normal diferansiyel denklem) çözücünüz varsa, şöyle görünebilir:

subroutine rungekutta(neq, t, tend, y, deriv)
  integer neq             ! number of differential equations
  double precision t      ! initial time
  double precision tend   ! final time
  double precision y(neq) ! state vector
  ! deriv is the callback function to evaluate the state derivative
  ...
  deriv(neq, t, y, yprime) ! call deriv to get the state derivative
  ...
  deriv(neq, t, y, yprime) ! call it several times
  ...
end subroutine

Arayanın, gerektiğinde çağrılacak özel amaçlı bir işlev ileterek altyordamın davranışını özelleştirmesini sağlar. Bu, ODE çözücünün çok çeşitli sistemleri simüle etmek için kullanılmasına izin verir.


1

Bunun üzerine tökezledi ve daha güncel bir cevap vermek istedim ...

Geri arama işlevleri, , daha sonra izin verir ve kodumuzun geri kalanını beklemek yerine çalışmasına izin verir. Eşzamansız kod, daha sonra herhangi bir şeyi yürütme lüksüne izin verir . Karşılaştığım geri arama işlevlerinin en okunabilir örneği JavaScript Vaatleridir. Aşağıdaki örnekte, işlev (sonuç) veya (newResult) veya (finalResult) işlevlerini her gördüğünüzde bunlar geri çağrı işlevleridir. Verileri sunucudan geri döndüğünde, süslü parantez içindeki kod yürütülür. Sadece bu noktada, ihtiyaç duydukları veriler mevcut olduğundan bu işlevleri yerine getirmek mantıklı olacaktır.

doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);

kod ... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises adresinden alınmıştır.

Umarım, bu birine yardımcı olur. Bu geri çağrıları anlamama yardımcı oldu :)


1
Bu, önceki 9
gnat

1
Belki senin için ama bu gerçekten benim için geri aramaları netleştiren şey bu yüzden paylaşacağımı düşündüm. IMO, örneğin okunabilirliği onu değerli kılan şeydir. Eminim kodun okunabilirliğinin özellikle yeni başlayanlar için uzun bir yol kat ettiğini kabul edebiliriz.
NRV

-2

Ben lua bilmiyorum ama genel olarak geri çağrı yöntemleri multithreading gibi bazı ne. Örneğin, mobil uygulama geliştirme programlamasında, uygulamaların çoğu sunucuya istek gönderme ve UI ile oynama gibi veriler sunucudan yanıt olarak geldi. Kullanıcı sunucuya bir istek gönderdiğinde, sunucudan yanıt almak zaman alacaktır, ancak en iyi UX kullanıcı arayüzü için takılmaması gerekir.

Bu nedenle paralel işlemler yapmak için birden fazla iplik kullanıyoruz. Sunucudan yanıt aldığımızda kullanıcı arayüzünü güncellememiz gerekiyor. güncellemek için bu konuyu bilgilendirmeliyiz. fonksiyonel dünyadan. Bu tür işlev çağrılarına geri çağrı yöntemleri denir. Bu yöntemleri çağırdığınızda, denetim ana iş parçacığına dönmelidir. Örneğin geri arama yöntemleri, objektif-C'deki bloklardır.


evet, söyledikleriniz kitabı okuduktan sonra anlayışımla tutarlı.
Lucas Li

2
Geri arama yöntemleri çoklu kullanım gibi bir şey değildir. Geri arama yöntemleri basitçe fonksiyon göstericileridir (delegeler). Konular CPU bağlamında anahtarlama / kullanım ile ilgilidir. Oldukça basitleştirilmiş bir kontrast, iş parçacığının UX için CPU optimizasyonu, geri çağrıların polimorfizm için bellek değiştirme ile ilgili olmasıdır. İş parçacıklarının geri arama gerçekleştirebilmesi, iş parçacığı ve geri aramaların benzer olduğu anlamına gelmez. İş parçacıkları da statik sınıflarda statik yöntemler yürütür, ancak iş parçacığı ve statik türler benzer değildir.
rism
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.