จะอธิบายการโทรกลับเป็นภาษาอังกฤษธรรมดาได้อย่างไร พวกเขาแตกต่างจากการเรียกฟังก์ชั่นหนึ่งจากฟังก์ชั่นอื่นหรือไม่?


342

จะอธิบายการโทรกลับเป็นภาษาอังกฤษธรรมดาได้อย่างไร พวกเขาแตกต่างจากการเรียกฟังก์ชั่นหนึ่งจากฟังก์ชั่นอื่นที่รับบริบทบางอย่างจากฟังก์ชั่นการโทรได้อย่างไร? พลังของพวกเขาจะถูกอธิบายต่อโปรแกรมเมอร์มือใหม่ได้อย่างไร?


1
ฉันเชื่อว่าชื่อทางวิทยาศาสตร์ของมันคือรูปแบบการส่งต่อ คุณสามารถค้นหาสิ่งนี้ได้บนวิกิ
ming_codes

1
มีบางคำตอบที่ดีสำหรับคำถามที่เหมือนกันใน Quoraด้วย
dbr

4
คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/824234/what-is-a-callback-function
moodywoody

คำอธิบายที่ดีที่สุดของการโทรกลับที่ฉันเคยพบyoutube.com/watch?v=xHneyv38Jro
Sameer Sinha

คำตอบ:


114

บ่อยครั้งที่แอปพลิเคชั่นต้องการเรียกใช้ฟังก์ชันที่แตกต่างกันตามบริบท / สถานะ สำหรับสิ่งนี้เราใช้ตัวแปรที่เราจะเก็บข้อมูลเกี่ยวกับฟังก์ชั่นที่จะเรียกว่า ตามความต้องการแอปพลิเคชันจะตั้งค่าตัวแปรนี้ด้วยข้อมูลเกี่ยวกับฟังก์ชันที่จะเรียกใช้และจะเรียกใช้ฟังก์ชันโดยใช้ตัวแปรเดียวกัน

ใน javascript ตัวอย่างอยู่ด้านล่าง ที่นี่เราใช้วิธีการโต้แย้งเป็นตัวแปรที่เราเก็บข้อมูลเกี่ยวกับฟังก์ชั่น

function processArray(arr, callback) {
    var resultArr = new Array(); 
    for (var i = arr.length-1; i >= 0; i--)
        resultArr[i] = callback(arr[i]);
    return resultArr;
}

var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]

18
ในขณะที่นี่คือเทคนิคการเรียกกลับคำอธิบายให้ฟังดูไม่ชัดเจนจากตัวชี้ฟังก์ชั่นทั่วไป มันจะช่วยในการรวมเหตุผลบางอย่างว่าทำไมโทรกลับอาจถูกนำมาใช้
Eric

4
ฉันไม่เข้าใจคำตอบนี้ มันเป็นมากกว่าการอธิบายมากกว่ารหัสหรือไม่
Abhishek Singh

ทำไมเราไม่ทำในสิ่งที่เราทำในฟังก์ชั่นโทรกลับ (the function(arg)) ในprocessArray(arr,callback)ฟังก์ชั่น
Abhi

1
@JoSmo คุณถูกต้องบางส่วน ผ่านตัวแปร + call-back-function เป็นพารามิเตอร์ที่สร้างผลลัพธ์ด้วยตัวแปรโดยฟังก์ชันต้นฉบับและส่งผ่านไปยังฟังก์ชัน call-back-function เพื่อการประมวลผลเพิ่มเติม ตัวอย่าง: func1 (a, callback_func) {v = a + 1} และมีฟังก์ชั่นการโทรกลับที่กำหนดไว้ล่วงหน้า: callback_func (v) {return v + 1;} สิ่งนี้จะเพิ่มขึ้น 2 ดังนั้นถ้าคุณผ่านอาร์กิวเมนต์ของจำนวนเต็ม 4 ใน พารามิเตอร์ "a" callback_funct จะส่งคืนผลลัพธ์ 6 อ่านcallbackhell.comนี้แหล่งที่ดีที่สุดที่ฉันพบ
Dung

คำตอบนี้ไม่ชัดเจน อาจจะง่ายและชัดเจน!
Arjun Kalidas

545

ฉันจะพยายามทำให้คนตายง่าย ๆ "โทรกลับ" เป็นฟังก์ชั่นใด ๆ ที่ถูกเรียกโดยฟังก์ชั่นอื่นซึ่งใช้ฟังก์ชั่นแรกเป็นพารามิเตอร์ บ่อยครั้งที่ "การโทรกลับ" เป็นฟังก์ชั่นที่ถูกเรียกเมื่อมีบางสิ่งเกิดขึ้น ว่าสิ่งที่สามารถเรียกว่า "เหตุการณ์" ในการเขียนโปรแกรมพูด

ลองนึกภาพสถานการณ์นี้: คุณคาดหวังแพคเกจในอีกสองสามวัน แพคเกจเป็นของขวัญสำหรับเพื่อนบ้านของคุณ ดังนั้นเมื่อคุณได้รับแพ็คเกจคุณต้องนำมันไปให้เพื่อนบ้าน คุณออกนอกเมืองแล้วดังนั้นคุณจึงทิ้งคำแนะนำสำหรับคู่สมรสของคุณ

คุณสามารถบอกพวกเขาเพื่อรับแพคเกจและนำไปให้เพื่อนบ้าน หากคู่สมรสของคุณโง่เหมือนคอมพิวเตอร์พวกเขาจะนั่งที่ประตูและรอพัสดุจนกว่ามันจะมา แต่มีวิธีที่ดีกว่า บอกคู่สมรสของคุณว่าเมื่อพวกเขาได้รับหีบห่อพวกเขาควรนำไปให้เพื่อนบ้าน จากนั้นพวกเขาสามารถใช้ชีวิตตามปกติจนกระทั่งได้รับแพ็คเกจ

ในตัวอย่างของเราการรับแพคเกจคือ "เหตุการณ์" และการนำไปยังเพื่อนบ้านคือ "การโทรกลับ" คู่สมรสของคุณ "รัน" คำแนะนำของคุณเพื่อนำแพคเกจมาเฉพาะเมื่อแพคเกจมาถึง ดีกว่ามาก!

ความคิดแบบนี้เห็นได้ชัดในชีวิตประจำวัน แต่คอมพิวเตอร์ไม่มีสามัญสำนึกแบบเดียวกัน พิจารณาว่าโปรแกรมเมอร์เขียนไฟล์อย่างไร:

fileObject = open(file)
# now that we have WAITED for the file to open, we can write to it
fileObject.write("We are writing to the file.")
# now we can continue doing the other, totally unrelated things our program does

ที่นี่เรารอให้ไฟล์เปิดก่อนที่เราจะเขียนลงไป "บล็อก" การไหลของการดำเนินการและโปรแกรมของเราไม่สามารถทำสิ่งอื่นใดที่อาจต้องทำ! ถ้าเราสามารถทำสิ่งนี้แทน:

# we pass writeToFile (A CALLBACK FUNCTION!) to the open function
fileObject = open(file, writeToFile)
# execution continues flowing -- we don't wait for the file to be opened
# ONCE the file is opened we write to it, but while we wait WE CAN DO OTHER THINGS!

ปรากฎว่าเราทำสิ่งนี้ด้วยภาษาและกรอบบางอย่าง มันเจ๋งมาก! ลองใช้Node.jsเพื่อฝึกฝนจริงด้วยความคิดแบบนี้


6
สิ่งนี้ถูกต้อง แต่ไม่ครอบคลุมกรณีการใช้งานทั่วไปทั้งหมดสำหรับการโทรกลับ บ่อยครั้งที่คุณใช้การเรียกกลับเมื่อคุณต้องการเรียกใช้ฟังก์ชันที่มีอาร์กิวเมนต์ซึ่งจะถูกประมวลผลในกระบวนการของฟังก์ชันอื่น ตัวอย่างเช่นใน PHP array_filter () และ array_map () รับการเรียกกลับที่จะเรียกในลูป
Haralan Dobrev

2
ตัวอย่างไฟล์เขียนเหมาะสมหรือไม่? ดูเหมือนว่าจะทำให้สมมติฐานเกี่ยวกับวิธีการopenทำงาน เป็นไปได้ที่openบล็อกภายในได้ในขณะที่รอให้ระบบปฏิบัติการทำเวทย์มนตร์ดำ ไม่มีความแตกต่างในผลลัพธ์ในกรณีดังกล่าว
Kenneth K.

23
คำอธิบายที่ดี แต่ฉันสับสนเล็กน้อย การโทรกลับเป็นแบบมัลติเธรดหรือไม่?
Premraj

1
เยี่ยมมาก! กำลังมองหาภาษาอังกฤษธรรมดาทั่วสถานที่และนี่คือครั้งแรกที่ฉันได้พบจนถึง :)
ChristoKiwi

1
อะไรทำให้ฟังก์ชั่นเปิดในตัวอย่างที่ไม่บล็อกของคุณ เปิดยังอาจป้องกันการไหลของการดำเนินการ ..
Koray Tugay

82

จะอธิบายการโทรกลับเป็นภาษาอังกฤษธรรมดาได้อย่างไร

ในภาษาอังกฤษธรรมดาฟังก์ชั่นการเรียกกลับเป็นเหมือนคนทำงานที่ "โทรกลับ" เพื่อเขาผู้จัดการเมื่อเขาได้เสร็จสิ้นการงาน

พวกเขาแตกต่างจากการเรียกฟังก์ชั่นหนึ่งจากฟังก์ชั่นอื่นที่รับบริบทบางอย่างจากฟังก์ชั่นการโทรได้อย่างไร?

เป็นความจริงที่ว่าคุณกำลังเรียกใช้ฟังก์ชันจากฟังก์ชันอื่น แต่ที่สำคัญคือการโทรกลับนั้นถือเป็นวัตถุดังนั้นคุณจึงสามารถเปลี่ยนฟังก์ชันที่จะเรียกได้ตามสถานะของระบบ (เช่นรูปแบบการออกแบบกลยุทธ์)

พลังของพวกเขาจะถูกอธิบายต่อโปรแกรมเมอร์มือใหม่ได้อย่างไร?

พลังของการเรียกกลับสามารถดูได้ง่ายในเว็บไซต์สไตล์ AJAX ที่ต้องการดึงข้อมูลจากเซิร์ฟเวอร์ การดาวน์โหลดข้อมูลใหม่อาจใช้เวลาสักครู่ ส่วนติดต่อผู้ใช้ทั้งหมดของคุณจะ "หยุด" ในขณะที่ดาวน์โหลดข้อมูลใหม่หรือคุณจะต้องรีเฟรชหน้าทั้งหมดแทนที่จะเป็นเพียงส่วนหนึ่ง ด้วยการโทรกลับคุณสามารถแทรกภาพ "กำลังโหลด" และแทนที่ด้วยข้อมูลใหม่เมื่อมีการโหลด

รหัสบางอย่างโดยไม่ต้องโทรกลับ:

function grabAndFreeze() {
    showNowLoading(true);
    var jsondata = getData('http://yourserver.com/data/messages.json');
    /* User Interface 'freezes' while getting data */
    processData(jsondata);
    showNowLoading(false);
    do_other_stuff(); // not called until data fully downloaded
}

function processData(jsondata) { // do something with the data
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

ด้วยการโทรกลับ:

นี่คือตัวอย่างที่มีการเรียกกลับโดยใช้ jQuery ฯgetJSON :

function processDataCB(jsondata) { // callback: update UI with results
   showNowLoading(false);
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

function grabAndGo() { // and don't freeze
    showNowLoading(true);
    $('#results_messages').html(now_loading_image);
    $.getJSON("http://yourserver.com/data/messages.json", processDataCB);
    /* Call processDataCB when data is downloaded, no frozen User Interface! */
    do_other_stuff(); // called immediately
}

ด้วยการปิด:

บ่อยครั้งที่ความต้องการในการเข้าถึงการติดต่อกลับstateจากฟังก์ชั่นการเรียกใช้closureซึ่งเป็นเหมือนคนทำงานจำเป็นต้องได้รับข้อมูลจากผู้จัดการก่อนที่เขาจะสามารถดำเนินการของเขางาน ในการสร้างclosureคุณสามารถอินไลน์ฟังก์ชันเพื่อดูข้อมูลในบริบทการโทร:

/* Grab messages, chat users, etc by changing dtable. Run callback cb when done.*/
function grab(dtable, cb) { 
    if (null == dtable) { dtable = "messages"; }
    var uiElem = "_" + dtable;
    showNowLoading(true, dtable);
    $('#results' + uiElem).html(now_loading_image);
    $.getJSON("http://yourserver.com/user/"+dtable+".json", cb || function (jsondata) {
       // Using a closure: can "see" dtable argument and uiElem variables above.
       var count = jsondata.results ? jsondata.results.length : 0, 
           counterMsg = ['Fetched', count, 'new', dtable].join(' '),
           // no new chatters/messages/etc
           defaultResultsMsg = ['(no new ', dtable, ')'].join(''); 
       showNowLoading(false, dtable);
       $('#counter' + uiElem).text(counterMsg);
       $('#results'+ uiElem).html(jsondata.results || defaultResultsMsg);
    });
    /* User Interface calls cb when data is downloaded */

    do_other_stuff(); // called immediately
}

การใช้งาน:

// update results_chatters when chatters.json data is downloaded:
grab("chatters"); 
// update results_messages when messages.json data is downloaded
grab("messages"); 
// call myCallback(jsondata) when "history.json" data is loaded:
grab("history", myCallback); 

การปิด

สุดท้ายนี่คือคำนิยามของclosureจากDouglas Crockford :

ฟังก์ชั่นสามารถกำหนดได้ภายในฟังก์ชั่นอื่น ๆ ฟังก์ชั่นภายในมีการเข้าถึง vars และพารามิเตอร์ของฟังก์ชั่นด้านนอก ถ้าการอ้างอิงถึงฟังก์ชันภายในยังคงอยู่ (ตัวอย่างเช่นในฐานะฟังก์ชันการเรียกกลับ) vars ของฟังก์ชันภายนอกยังสามารถอยู่รอดได้

ดูสิ่งนี้ด้วย:


12
+1 วรรคแรกคือปังเงิน อย่างไรก็ตามส่วนที่เหลือของมันจะเข้าสู่ศัพท์แสงวิทยาศาสตร์คอมพิวเตอร์ค่อนข้างเร็ว
TarkaDaal

41

ฉันตะลึงเมื่อเห็นคนฉลาดจำนวนมากที่ล้มเหลวในการตอกย้ำความจริงที่คำว่า "โทรกลับ" ได้ถูกนำมาใช้ในสองวิธีที่ไม่สอดคล้องกัน

ทั้งสองวิธีเกี่ยวข้องกับการปรับแต่งฟังก์ชั่นโดยการส่งฟังก์ชั่นเพิ่มเติม (การกำหนดฟังก์ชั่น, ไม่ระบุชื่อหรือตั้งชื่อ) ไปยังฟังก์ชั่นที่มีอยู่ กล่าวคือ

customizableFunc(customFunctionality)

หากฟังก์ชันการทำงานที่กำหนดเองนั้นเสียบเข้ากับบล็อคโค้ดคุณได้ปรับแต่งฟังก์ชั่นเช่นนั้น

    customizableFucn(customFunctionality) {
      var data = doSomthing();
      customFunctionality(data);
      ...
    }

แม้ว่าฟังก์ชั่นการฉีดแบบนี้มักจะเรียกว่า "การโทรกลับ" แต่ก็ไม่มีอะไรเกิดขึ้นกับมัน ตัวอย่างที่ชัดเจนมากคือวิธี forEach ซึ่งมีฟังก์ชั่นที่กำหนดเองให้เป็นอาร์กิวเมนต์ที่จะใช้กับแต่ละองค์ประกอบในอาร์เรย์เพื่อปรับเปลี่ยนอาร์เรย์

แต่นี่คือพื้นฐานที่แตกต่างจากการใช้ฟังก์ชั่น "โทรกลับ" สำหรับการเขียนโปรแกรมอะซิงโครนัสเช่นเดียวกับใน AJAX หรือ node.js หรือเพียงแค่การกำหนดฟังก์ชั่นให้กับกิจกรรมการโต้ตอบผู้ใช้ (เช่นการคลิกเมาส์) ในกรณีนี้แนวคิดทั้งหมดคือการรอให้เหตุการณ์เกิดขึ้นก่อนที่จะดำเนินการฟังก์ชันการทำงานที่กำหนดเอง สิ่งนี้ชัดเจนในกรณีของการโต้ตอบกับผู้ใช้ แต่ก็มีความสำคัญในกระบวนการ i / o (อินพุต / เอาต์พุต) ที่อาจต้องใช้เวลาเช่นการอ่านไฟล์จากดิสก์ นี่คือที่คำว่า "โทรกลับ" ทำให้รู้สึกชัดเจนที่สุด เมื่อกระบวนการ i / o เริ่มต้นขึ้น (เช่นขอให้ไฟล์อ่านจากดิสก์หรือเซิร์ฟเวอร์เพื่อส่งคืนข้อมูลจากการร้องขอ HTTP) แบบอะซิงโครนัสโปรแกรมไม่รอให้เสร็จ มันสามารถไปข้างหน้ากับสิ่งที่งานที่กำหนดไว้ต่อไปและตอบสนองกับฟังก์ชั่นที่กำหนดเองเท่านั้นหลังจากที่ได้รับแจ้งว่าการอ่านไฟล์หรือคำขอ http เสร็จสมบูรณ์ (หรือล้มเหลว) และข้อมูลที่มีอยู่ในฟังก์ชั่นที่กำหนดเอง มันเหมือนกับการโทรหาธุรกิจทางโทรศัพท์และปล่อยให้หมายเลข "โทรกลับ" ของคุณดังนั้นพวกเขาจึงสามารถโทรหาคุณได้เมื่อมีคนพร้อมที่จะติดต่อกลับ ดีกว่าแขวนอยู่บนเส้นเพราะใครจะรู้ว่านานแค่ไหนและไม่สามารถเข้าร่วมกิจกรรมอื่น ๆ ได้

การใช้แบบอะซิงโครนัสโดยเนื้อแท้เกี่ยวข้องกับวิธีการฟังสำหรับเหตุการณ์ที่ต้องการ (เช่นความสมบูรณ์ของกระบวนการ i / o) ดังนั้นเมื่อมันเกิดขึ้น (และเมื่อเกิดขึ้น) ฟังก์ชันการเรียกกลับ "แบบกำหนดเอง" จะถูกดำเนินการ ในตัวอย่าง AJAX ที่เห็นได้ชัดเมื่อข้อมูลมาถึงจากเซิร์ฟเวอร์จริง ๆ ฟังก์ชั่น "โทรกลับ" จะถูกเรียกให้ใช้ข้อมูลนั้นเพื่อแก้ไข DOM และดังนั้นจึงวาดหน้าต่างเบราว์เซอร์ขึ้นมาใหม่

เพื่อสรุป บางคนใช้คำว่า "โทรกลับ" เพื่ออ้างถึงฟังก์ชั่นที่กำหนดเองทุกชนิดที่สามารถแทรกลงในฟังก์ชั่นที่มีอยู่เป็นอาร์กิวเมนต์ แต่สำหรับฉันแล้วอย่างน้อยที่สุดการใช้คำที่เหมาะสมที่สุดก็คือฟังก์ชั่น "โทรกลับ" แบบฉีดที่ถูกใช้แบบอะซิงโครนัส - จะถูกดำเนินการเฉพาะเมื่อมีเหตุการณ์ที่กำลังรอการแจ้งเตือนเท่านั้น


ดังนั้นเมื่อฟังก์ชั่นโทรกลับกระบวนการจะกลับไปอยู่ที่ไหน? ตัวอย่างเช่นหากมีรหัสสี่บรรทัด 1.fileObject = open (ไฟล์ writeToFile); 2. doSomething1 (); 3. doSomething2 (); 4. doSomething3 ()
MagicLAMP

บรรทัดที่ 1 จะถูกดำเนินการ แต่แทนที่จะรอให้ไฟล์ที่จะเปิดไปที่บรรทัด 2 จากนั้น 3 ณ จุดนั้นไฟล์จะเปิดและ (เมื่อบรรทัดที่ 3 เสร็จสิ้นการดำเนินการส่งสัญญาณใด ๆ ) โทรกลับไปที่เคาน์เตอร์โปรแกรมจะพูดว่า " ผ่านการควบคุมเพื่อ writeToFile "ซึ่งทำสิ่งต่าง ๆ และเมื่อเสร็จสิ้นผ่านการควบคุมกลับไปยังจุดที่เกิด INT ในบรรทัดที่ 3 หรือไปยังบรรทัดที่ 4 หากบรรทัดที่ 3 ได้เสร็จสิ้น
MagicLAMP

1
นี่คือคำอธิบายที่ชัดเจนมากของจุดสำคัญอื่น ๆ : เช่นความแตกต่างระหว่างฟังก์ชั่นที่ส่งผ่านในขณะที่ ARG Array.prototype.forEach()และฟังก์ชั่นที่ส่งผ่านเป็น ARG ไปsetTimeout()และพวกเขาเป็นม้าสีที่แตกต่างกันเท่าที่คุณเหตุผลเกี่ยวกับโปรแกรมของคุณ .
mikermcneil

26

ในเงื่อนไขที่ไม่ใช่โปรแกรมเมอร์การเรียกกลับเป็นแบบเติมคำในโปรแกรม

รายการทั่วไปในหลายรูปแบบกระดาษคือ "บุคคลที่จะโทรในกรณีฉุกเฉิน" มีบรรทัดว่างอยู่ที่นั่น คุณเขียนชื่อและหมายเลขโทรศัพท์ของใครบางคน หากเกิดเหตุฉุกเฉินบุคคลนั้นจะถูกเรียก

  • ทุกคนได้รับฟอร์มว่างเปล่าเหมือนกัน แต่
  • ทุกคนสามารถเขียนหมายเลขติดต่อฉุกเฉินที่แตกต่างกัน

นี่คือกุญแจสำคัญ คุณไม่ได้เปลี่ยนรูปแบบ (รหัสมักจะเป็นคนอื่น) อย่างไรก็ตามคุณสามารถกรอกข้อมูลที่ขาดหายไป ( หมายเลขของคุณ )

ตัวอย่างที่ 1:

การโทรกลับถูกใช้เป็นวิธีการที่กำหนดเองซึ่งอาจใช้สำหรับการเพิ่ม / เปลี่ยนพฤติกรรมของโปรแกรม ตัวอย่างเช่นรับรหัส C ที่ทำหน้าที่ฟังก์ชั่น แต่ไม่รู้ว่าจะพิมพ์งานได้อย่างไร สิ่งที่มันสามารถทำได้คือสร้างสตริง เมื่อพยายามหาว่าจะทำอย่างไรกับสตริงมันจะเห็นบรรทัดว่าง แต่โปรแกรมเมอร์ให้คุณว่างเพื่อเขียนโทรกลับของคุณใน!

set_print_callback(the_callback)ในตัวอย่างนี้คุณไม่ได้ใช้ดินสอกรอกข้อมูลลงในที่ว่างเปล่าบนแผ่นกระดาษที่คุณใช้ฟังก์ชั่น

  • ตัวแปรว่างในโมดูล / รหัสคือบรรทัดว่าง
  • set_print_callback เป็นดินสอ
  • และthe_callbackเป็นข้อมูลของคุณที่คุณกรอก

ตอนนี้คุณได้กรอกข้อมูลในบรรทัดว่างในโปรแกรม เมื่อใดก็ตามที่ต้องการพิมพ์ผลลัพธ์มันจะดูบรรทัดว่างนั้นและทำตามคำแนะนำที่นั่น (เช่นเรียกใช้ฟังก์ชันที่คุณใส่ไว้) ในทางปฏิบัติสิ่งนี้ช่วยให้สามารถพิมพ์หน้าจอเป็นไฟล์บันทึกไปยังเครื่องพิมพ์ ผ่านการเชื่อมต่อเครือข่ายหรือการรวมกันใด ๆ คุณได้เติมสิ่งที่คุณต้องการทำในช่องว่าง

ตัวอย่างที่ 2:

เมื่อคุณได้รับแจ้งว่าคุณต้องโทรไปยังหมายเลขฉุกเฉินคุณจะไปและอ่านสิ่งที่เขียนในแบบฟอร์มกระดาษแล้วโทรไปยังหมายเลขที่คุณอ่าน หากบรรทัดนั้นว่างเปล่าจะไม่มีการดำเนินการใด ๆ

การเขียนโปรแกรม Gui ทำงานในลักษณะเดียวกัน เมื่อมีการคลิกปุ่มโปรแกรมจำเป็นต้องรู้ว่าจะทำอย่างไรต่อไป มันไปและมองหาการโทรกลับ การเรียกกลับนี้เกิดขึ้นในช่องว่างที่มีข้อความว่า "นี่คือสิ่งที่คุณทำเมื่อมีการคลิกที่ปุ่ม 1"

IDEs ส่วนใหญ่จะเติมช่องว่างให้คุณโดยอัตโนมัติ (เขียนวิธีการพื้นฐาน) เมื่อคุณขอให้ (เช่นbutton1_clicked) แต่ว่างเปล่าที่สามารถมีวิธีการใด ๆ ที่คุณยี้กันโปรด คุณสามารถเรียกวิธีการrun_computationsหรือbutter_the_biscuitsตราบเท่าที่คุณใส่ชื่อของการโทรกลับนั้นว่างเปล่าที่เหมาะสม คุณสามารถใส่ "555-555-1212" ในหมายเลขฉุกเฉินที่ว่างเปล่า มันไม่สมเหตุสมผล แต่ก็อนุญาต


หมายเหตุสุดท้าย: บรรทัดว่างที่คุณกรอกด้วยการโทรกลับหรือไม่ สามารถลบและเขียนใหม่ได้ตามต้องการ (ไม่ว่าคุณจะเป็นคำถามอื่นหรือไม่ แต่เป็นส่วนหนึ่งของพลังของพวกเขา)


22

ดีกว่าเสมอที่จะเริ่มต้นด้วยตัวอย่าง :)

สมมติว่าคุณมีสองโมดูล A และ B

คุณต้องการให้โมดูล A ถูกแจ้งเตือนเมื่อมีเหตุการณ์ / เงื่อนไขบางอย่างเกิดขึ้นในโมดูล B อย่างไรก็ตามโมดูล B ไม่มีความคิดเกี่ยวกับโมดูล A ของคุณสิ่งที่รู้คือที่อยู่ของฟังก์ชันเฉพาะ (ของโมดูล A) ผ่านตัวชี้ฟังก์ชันที่ จัดทำโดยโมดูล A

ดังนั้นสิ่งที่ B ต้องทำตอนนี้คือ "การเรียกกลับ" ในโมดูล A เมื่อเหตุการณ์ / เงื่อนไขเฉพาะเกิดขึ้นโดยใช้ตัวชี้ฟังก์ชัน สามารถทำการประมวลผลเพิ่มเติมภายในฟังก์ชั่นการโทรกลับ

*) ข้อได้เปรียบที่ชัดเจนที่นี่คือคุณสรุปทุกอย่างเกี่ยวกับโมดูล A จากโมดูล B โมดูล B ไม่จำเป็นต้องสนใจว่าใคร / โมดูล A คืออะไร


ดังนั้นพารามิเตอร์ของฟังก์ชั่นใน A นั้นถูกจัดเตรียมไว้ในโมดูล B ว่าถูกต้องหรือไม่?
U.Savas

21

ลองนึกภาพคุณต้องใช้ฟังก์ชันที่ส่งคืน 10 กำลังสองเพื่อให้คุณเขียนฟังก์ชัน:

function tenSquared() {return 10*10;}

หลังจากนั้นคุณต้องมี 9 กำลังสองเพื่อให้คุณเขียนฟังก์ชันอื่น:

function nineSquared() {return 9*9;}

ในที่สุดคุณจะแทนที่สิ่งเหล่านี้ด้วยฟังก์ชันทั่วไป:

function square(x) {return x*x;}

การคิดแบบเดียวกันนั้นใช้กับการโทรกลับ คุณมีฟังก์ชั่นที่ทำงานบางอย่างและเมื่อโทรออก doA:

function computeA(){
    ...
    doA(result);
}

หลังจากนั้นคุณต้องการฟังก์ชั่นที่เหมือนกันเพื่อเรียกใช้ doB แทนคุณสามารถทำซ้ำฟังก์ชันทั้งหมด:

function computeB(){
    ...
    doB(result);
}

หรือคุณสามารถส่งผ่านฟังก์ชันการโทรกลับเป็นตัวแปรและจะต้องมีฟังก์ชันหนึ่งครั้ง:

function compute(callback){
    ...
    callback(result);
}

จากนั้นคุณต้องเรียกใช้ compute (doA) และ compute (doB)

นอกเหนือจากรหัสที่ทำให้เข้าใจง่ายแล้วมันยังให้รหัสแบบอะซิงโครนัสแจ้งให้คุณทราบว่ามันเสร็จสมบูรณ์โดยการเรียกฟังก์ชั่นโดยพลการของคุณเมื่อทำเสร็จคล้ายกับเมื่อคุณโทรหาใครบางคนทางโทรศัพท์และออกหมายเลขโทรกลับ


ดังนั้นคุณจะผ่านฟังก์ชั่นเป็นพารามิเตอร์ ภาษาการเขียนโปรแกรมทั้งหมดอนุญาตให้ส่งผ่านฟังก์ชันเป็นพารามิเตอร์หรือไม่ ถ้าไม่เช่นนั้นคุณสามารถแสดงตัวอย่างวิธีใช้ฟังก์ชันการโทรกลับในภาษาเหล่านั้นได้อย่างไร
Quazi Irfan

21

Johny โปรแกรมเมอร์ต้องการเครื่องเย็บกระดาษดังนั้นเขาจึงลงไปที่แผนกเครื่องใช้สำนักงานและขอหนึ่งเครื่องหลังจากกรอกแบบฟอร์มคำขอเขาสามารถยืนที่นั่นและรอให้เสมียนไปดูรอบ ๆ คลังสินค้าสำหรับเครื่องเย็บกระดาษ (เช่นการเรียกฟังก์ชันปิดกั้น ) หรือไปทำอย่างอื่นระหว่างนี้

ตั้งแต่นี้มักจะใช้เวลา johny วางบันทึกพร้อมกับแบบฟอร์มขอให้พวกเขาโทรหาเขาเมื่อเครื่องเย็บกระดาษพร้อมสำหรับการหยิบดังนั้นในขณะเดียวกันเขาสามารถไปทำสิ่งอื่นเช่นนอนหลับบนโต๊ะของเขา


1
ดูเหมือนว่าจะมีความคล้ายคลึงกับสัญญามากกว่าการโทรกลับ: blog.jcoglan.com/2013/03/30/…
โธมัส

2
สัญญาเป็นเพียงน้ำตาลประโยครอบ ๆ การเรียกกลับ
Deven Phillips

11

คุณรู้สึกไม่สบายคุณจึงไปหาหมอ เขาตรวจสอบคุณและกำหนดว่าคุณต้องการยาอะไรบ้าง เขากำหนดยาและเรียกใบสั่งยาในร้านขายยาในพื้นที่ของคุณ คุณกลับบ้าน. หลังจากนั้นร้านขายยาของคุณโทรมาเพื่อบอกคุณว่าใบสั่งยาของคุณพร้อมแล้ว คุณไปรับมัน


การเปรียบเทียบที่ดีมาก คุณช่วยขยายอีกหน่อยได้ไหมบางทีตัวอย่างที่เกี่ยวข้องกับการเขียนโปรแกรม (ง่าย)?
a20

10

มีสองประเด็นที่จะอธิบายหนึ่งคือวิธีการโทรกลับทำงาน (ผ่านรอบฟังก์ชั่นที่สามารถเรียกได้โดยไม่ต้องรู้บริบทของมัน), อื่น ๆ สิ่งที่มันใช้สำหรับ (การจัดการเหตุการณ์แบบอะซิงโครนัส)

การเปรียบเทียบการรอพัสดุมาถึงที่มีการใช้โดยคำตอบอื่น ๆ เป็นสิ่งที่ดีที่จะอธิบายทั้ง ในโปรแกรมคอมพิวเตอร์คุณจะบอกให้คอมพิวเตอร์คาดหวังพัสดุ ตามปกติตอนนี้มันจะนั่งอยู่ที่นั่นและรอ (และไม่ทำอะไรเลย) จนกว่าพัสดุจะมาถึงอาจเป็นไปเรื่อย ๆ หากไม่เคยมาถึง สำหรับมนุษย์นี่ฟังดูงี่เง่า แต่ไม่มีมาตรการเพิ่มเติมนี่เป็นเรื่องธรรมชาติสำหรับคอมพิวเตอร์

ตอนนี้การติดต่อกลับจะเป็นเสียงระฆังที่ประตูหน้าของคุณ คุณให้บริการพัสดุด้วยวิธีที่จะแจ้งให้คุณทราบถึงการมาถึงของพัสดุโดยที่พวกเขาไม่ต้องรู้ว่าคุณอยู่ที่ไหนในบ้าน (แม้ว่าจะ) หรือว่าระฆังทำงานอย่างไร (ตัวอย่างเช่น "ระฆัง" บางคนส่งสายจริง) เนื่องจากคุณได้จัดเตรียม "ฟังก์ชันการโทรกลับ" ที่สามารถ "เรียก" ได้ทุกเวลานอกบริบทคุณสามารถหยุดนั่งที่ระเบียงด้านหน้าและ "จัดการกับ เหตุการณ์ "(ของการมาถึงของพัสดุ) เมื่อใดก็ตามที่ถึงเวลา


นี่เป็นภาษาอังกฤษธรรมดา
Jeb50

นี่น่าจะเป็นคำอธิบายที่ดีที่สุด!
Vishal Sharma

6

ลองนึกภาพเพื่อนกำลังออกจากบ้านของคุณและคุณบอกเธอว่า "โทรหาฉันเมื่อคุณกลับถึงบ้านเพื่อให้ฉันรู้ว่าคุณมาถึงอย่างปลอดภัย"; ที่เป็น (ตัวอักษร) กกลับโทร นั่นคือสิ่งที่ฟังก์ชั่นการโทรกลับโดยไม่คำนึงถึงภาษา คุณต้องการให้ขั้นตอนบางอย่างผ่านการควบคุมกลับไปที่คุณเมื่อมันเสร็จสิ้นงานดังนั้นคุณจึงให้ฟังก์ชันที่จะใช้ในการโทรกลับหาคุณ

ใน Python เช่น

grabDBValue( (lambda x: passValueToGUIWindow(x) ))

grabDBValueสามารถเขียนได้เฉพาะคว้าค่าจากฐานข้อมูลจากนั้นให้คุณระบุสิ่งที่ต้องทำจริง ๆ กับค่าดังนั้นจึงยอมรับฟังก์ชั่น คุณไม่รู้ว่าgrabDBValueจะกลับมาเมื่อไรหรืออย่างไรแต่ถ้าเป็นเช่นนั้นคุณรู้ว่าคุณต้องการให้มันทำอะไร ที่นี่ฉันผ่านในฟังก์ชั่นที่ไม่ระบุชื่อ (หรือแลมบ์ดา ) ที่ส่งค่าไปยังหน้าต่าง GUI ฉันสามารถเปลี่ยนพฤติกรรมของโปรแกรมได้อย่างง่ายดายโดยทำสิ่งนี้:

grabDBValue( (lambda x: passToLogger(x) ))

การเรียกกลับทำงานได้ดีในภาษาที่ฟังก์ชันมีค่าคลาสเช่นเดียวกับจำนวนเต็มปกติสตริงอักขระบูลีนและอื่น ๆ ใน C คุณสามารถ "ส่ง" ฟังก์ชันรอบ ๆ ได้โดยการส่งตัวชี้ไปยังผู้เรียก ใน Java ผู้เรียกจะถามคลาสคงที่ของประเภทที่มีชื่อวิธีการบางอย่างเนื่องจากไม่มีฟังก์ชั่น ("วิธีการ" จริงๆ) นอกชั้นเรียน; และในภาษาไดนามิกอื่น ๆ ส่วนใหญ่คุณสามารถส่งผ่านฟังก์ชั่นที่มีไวยากรณ์ง่าย ๆ

protip:

ในภาษาที่มีการกำหนดขอบเขตศัพท์ (เช่น Scheme หรือ Perl) คุณสามารถใช้เล่ห์เหลี่ยมเช่นนี้:

my $var = 2;
my $val = someCallerBackFunction(sub callback { return $var * 3; });
# Perlistas note: I know the sub doesn't need a name, this is for illustration

$valในกรณีนี้จะเป็น6เพราะการเรียกกลับมีการเข้าถึงตัวแปรที่ประกาศในสภาพแวดล้อมคำที่มันถูกกำหนดไว้ ขอบเขตคำศัพท์และการเรียกกลับที่ไม่ระบุชื่อเป็นชุดค่าผสมที่มีประสิทธิภาพรับประกันการศึกษาเพิ่มเติมสำหรับโปรแกรมเมอร์สามเณร


1
+1 ฉันชอบคำตอบนี้จริงๆ คำอธิบายของสิ่งที่เรียกกลับเป็นเป็นเรื่องง่ายและรัดกุม
TarkaDaal

6

คุณมีรหัสที่คุณต้องการเรียกใช้ โดยปกติเมื่อคุณเรียกว่าคุณกำลังรอให้เสร็จก่อนที่จะดำเนินการต่อ (ซึ่งอาจทำให้แอปของคุณเป็นสีเทา / ทำให้เวลาเคอร์เซอร์หมุน)

วิธีอื่นคือการเรียกใช้รหัสนี้ในแบบคู่ขนานและดำเนินการกับงานของคุณเอง แต่ถ้ารหัสต้นฉบับของคุณจำเป็นต้องทำสิ่งต่าง ๆ โดยขึ้นอยู่กับการตอบสนองจากโค้ดที่เรียกว่า ในกรณีนี้คุณสามารถส่งผ่านชื่อ / ที่ตั้งของรหัสที่คุณต้องการให้โทรเมื่อทำเสร็จ นี่คือ "โทรกลับ"

รหัสปกติ: ขอข้อมูล -> ข้อมูลกระบวนการ -> จัดการกับผลลัพธ์ของการประมวลผล -> ทำสิ่งอื่น ๆ ต่อไป

ด้วยการเรียกกลับ: ขอข้อมูล -> ข้อมูลกระบวนการ -> ทำสิ่งอื่นต่อไป และในเวลาต่อมา -> จัดการกับผลลัพธ์ของการประมวลผล


6

โดยไม่ต้องโทรกลับค่าอื่น ๆ ทรัพยากรพิเศษการเขียนโปรแกรม (เช่นเกลียว, และอื่น ๆ ) โปรแกรมนั้นตรงกับลำดับของคำสั่งที่จะดำเนินการตามลำดับหนึ่งหลังจากที่อื่นและแม้จะมีชนิดของ "พฤติกรรมแบบไดนามิก" กำหนดโดยเงื่อนไขบางอย่างซึ่งเป็นสถานการณ์ที่เป็นไปได้ทั้งหมด จะถูกตั้งโปรแกรมไว้ก่อนหน้านี้

ดังนั้นหากเราต้องการมอบพฤติกรรมแบบไดนามิกที่แท้จริงให้กับโปรแกรมเราสามารถใช้การติดต่อกลับ ด้วยการเรียกกลับคุณสามารถสั่งให้พารามิเตอร์โปรแกรมเรียกโปรแกรมอื่นที่ให้พารามิเตอร์ที่กำหนดไว้ก่อนหน้านี้และสามารถคาดหวังผลลัพธ์บางอย่าง ( นี่คือสัญญาหรือลายเซ็นการดำเนินการ ) ดังนั้นผลลัพธ์เหล่านี้สามารถผลิต / ประมวลผลโดยโปรแกรมของบุคคลที่สาม ไม่เคยรู้จักมาก่อน

เทคนิคนี้เป็นพื้นฐานของความหลากหลายที่นำไปใช้กับโปรแกรมฟังก์ชั่นวัตถุและความเป็นเอกภาพอื่น ๆ ของรหัสที่ใช้งานโดยคอมพิวเตอร์

โลกมนุษย์ที่ใช้เป็นตัวอย่างในการติดต่อกลับเป็นคำอธิบายที่ดีเมื่อคุณทำงานบางอย่างให้สมมติว่าคุณเป็นจิตรกร ( ที่นี่คุณเป็นโปรแกรมหลักวาดภาพนั้น ) และโทรหาลูกค้าของคุณในบางครั้งเพื่อขอให้เขาอนุมัติผลงานของคุณ ดังนั้นเขาตัดสินใจว่ารูปภาพดีหรือไม่ ( ลูกค้าของคุณเป็นโปรแกรมบุคคลที่สาม )

ในตัวอย่างข้างต้นคุณเป็นจิตรกรและ "มอบหมาย" ให้ผู้อื่นงานอนุมัติผลรูปภาพเป็นพารามิเตอร์และลูกค้าใหม่ (เรียกว่า "ฟังก์ชั่น" เรียกกลับ) แต่ละคนเปลี่ยนผลลัพธ์ของงานของคุณตัดสินใจสิ่งที่เขาต้องการ เกี่ยวกับรูปภาพ ( การตัดสินใจของลูกค้าเป็นผลลัพธ์ที่ส่งคืนจาก "ฟังก์ชันการเรียกกลับ" )

ฉันหวังว่าคำอธิบายนี้จะเป็นประโยชน์


6

สมมติว่าคุณกำลังจะให้ฉันทำงานที่อาจเกิดขึ้นในระยะยาว: รับชื่อของคนห้าคนแรกที่คุณเจอ อาจใช้เวลาหลายวันถ้าฉันอยู่ในพื้นที่ที่มีประชากรเบาบาง คุณไม่สนใจนั่งอยู่ในมือของคุณในขณะที่ฉันกำลังวิ่งไปรอบ ๆ คุณจึงพูดว่า "เมื่อคุณมีรายชื่อแล้วโทรหาฉันที่เซลล์ของฉันแล้วอ่านกลับมาหาฉันนี่คือหมายเลข"

คุณได้ให้การอ้างอิงการโทรกลับ - ฟังก์ชั่นที่ฉันควรจะดำเนินการเพื่อส่งมอบการประมวลผลเพิ่มเติม

ใน JavaScript อาจมีลักษณะเช่นนี้:

var lottoNumbers = [];
var callback = function(theNames) {
  for (var i=0; i<theNames.length; i++) {
    lottoNumbers.push(theNames[i].length);
  }
};

db.executeQuery("SELECT name " +
                "FROM tblEveryOneInTheWholeWorld " +
                "ORDER BY proximity DESC " +
                "LIMIT 5", callback);

while (lottoNumbers.length < 5) {
  playGolf();
}
playLotto(lottoNumbers);

สิ่งนี้อาจปรับปรุงได้หลายวิธี เช่นคุณสามารถโทรกลับครั้งที่สองได้: หากใช้เวลานานกว่าหนึ่งชั่วโมงให้โทรไปที่โทรศัพท์สีแดงแล้วบอกคนที่ตอบว่าคุณหมดเวลาแล้ว


6

คำอธิบายการโทรกลับนั้นง่ายที่สุดในแง่ของระบบโทรศัพท์ ฟังก์ชั่นการโทรนั้นคล้ายคลึงกับการโทรหาใครบางคนทางโทรศัพท์ถามคำถามรับคำตอบและวางสาย การเพิ่มการโทรกลับจะเปลี่ยนการเปรียบเทียบดังนั้นหลังจากถามคำถามคุณคุณจะให้ชื่อและหมายเลขของเธอกับเธอเพื่อให้เธอสามารถโทรกลับหาคุณด้วยคำตอบ - Paul Jakubik "การดำเนินการติดต่อกลับใน C ++"


คำอธิบายที่ง่ายกว่าคือ: ฉันโทรหาใครสักคนเธอกำลังประชุมฉันฝากเบอร์โทรศัพท์ไว้เธอโทรกลับ
Lonely

5

การเรียกกลับเป็นฟังก์ชั่นที่จะถูกเรียกโดยฟังก์ชั่นที่สอง ฟังก์ชั่นที่สองนี้ไม่ทราบล่วงหน้าว่าจะมีฟังก์ชั่นอะไร ดังนั้นตัวตนของฟังก์ชั่นการโทรกลับจะถูกเก็บไว้ที่ใดที่หนึ่งหรือส่งผ่านไปยังฟังก์ชั่นที่สองเป็นพารามิเตอร์ "identity" นี้ขึ้นอยู่กับภาษาการเขียนโปรแกรมอาจเป็นที่อยู่ของการติดต่อกลับหรือตัวชี้ประเภทอื่น ๆ หรืออาจเป็นชื่อของฟังก์ชัน ตัวการเหมือนกันเราเก็บหรือส่งข้อมูลบางอย่างที่ระบุฟังก์ชันอย่างไม่น่าสงสัย

เมื่อถึงเวลาฟังก์ชั่นที่สองสามารถโทรกลับได้โดยระบุพารามิเตอร์ขึ้นอยู่กับสถานการณ์ในขณะนั้น มันอาจเลือกการโทรกลับจากชุดการโทรกลับที่เป็นไปได้ ภาษาการเขียนโปรแกรมต้องมีไวยากรณ์บางอย่างเพื่อให้ฟังก์ชันที่สองสามารถโทรกลับได้โดยรู้ว่า "ตัวตน"

กลไกนี้มีประโยชน์มากมาย ด้วยการเรียกกลับผู้ออกแบบฟังก์ชั่นสามารถให้มันปรับแต่งได้โดยให้มันเรียกสิ่งที่มีการเรียกกลับ ตัวอย่างเช่นฟังก์ชั่นการเรียงลำดับอาจใช้การเรียกกลับเป็นพารามิเตอร์และการเรียกกลับนี้อาจเป็นฟังก์ชันสำหรับการเปรียบเทียบสององค์ประกอบเพื่อตัดสินใจว่าจะใช้องค์ประกอบใดมาก่อน

ทั้งนี้ขึ้นอยู่กับภาษาการเขียนโปรแกรมคำว่า "ฟังก์ชั่น" ในการสนทนาข้างต้นอาจถูกแทนที่ด้วย "บล็อก" "ปิด" "แลมบ์ดา" ฯลฯ


5

เรามักจะส่งตัวแปรไปยังฟังก์ชั่น สมมติว่าคุณมีงานที่ต้องประมวลผลตัวแปรก่อนที่จะได้รับเป็นอาร์กิวเมนต์ - คุณสามารถใช้โทรกลับ

function1(var1, var2) เป็นวิธีปกติ

ถ้าฉันต้องการvar2ประมวลผลแล้วส่งเป็นอาร์กิวเมนต์? function1(var1, function2(var2))

นี่คือการเรียกกลับหนึ่งประเภท - ที่function2เรียกใช้งานโค้ดบางส่วนและส่งกลับตัวแปรกลับไปที่ฟังก์ชันเริ่มต้น


2
การติดต่อกลับประเภทอื่นคืออะไร
johnny

@johnny: มีการเรียกกลับเบราว์เซอร์ที่ปกติจะถูกเรียกเมื่ออาแจ็กซ์เป็นที่เรียบร้อย ฯลฯ
Nishant

4

คำอธิบายเชิงเปรียบเทียบ:

ฉันมีพัสดุที่ฉันต้องการส่งถึงเพื่อนและฉันก็ต้องการทราบเมื่อเพื่อนของฉันได้รับ

ดังนั้นฉันจึงนำพัสดุไปที่ที่ทำการไปรษณีย์และขอให้พวกเขาส่งมอบ หากฉันต้องการทราบว่าเมื่อเพื่อนของฉันรับพัสดุฉันมีสองตัวเลือก:

(a) ฉันสามารถรอที่ไปรษณีย์จนกว่าจะมีการจัดส่ง

(b) ฉันจะได้รับอีเมลเมื่อมีการจัดส่ง

ตัวเลือก (b) คล้ายกับการโทรกลับ


4

สำหรับการสอนการเรียกกลับคุณต้องสอนตัวชี้ก่อน เมื่อนักเรียนเข้าใจแนวคิดของตัวชี้ไปยังตัวแปรแล้วแนวคิดของการเรียกกลับจะง่ายขึ้น สมมติว่าคุณใช้ C / C ++ ขั้นตอนเหล่านี้สามารถติดตามได้

  • ก่อนอื่นให้นักเรียนดูวิธีใช้และจัดการตัวแปรโดยใช้ตัวชี้พร้อมกับการใช้ตัวระบุตัวแปรปกติ
  • จากนั้นสอนพวกเขาว่ามีสิ่งต่าง ๆ ที่สามารถทำได้กับพอยน์เตอร์เท่านั้น (เช่นผ่านตัวแปรโดยการอ้างอิง)
  • จากนั้นบอกพวกเขาว่าโค้ดหรือฟังก์ชันที่เรียกใช้งานได้นั้นเหมือนกับข้อมูลอื่น ๆ (หรือตัวแปร) ในหน่วยความจำอย่างไร ดังนั้นฟังก์ชั่นยังมีที่อยู่หรือพอยน์เตอร์
  • จากนั้นแสดงวิธีเรียกใช้ฟังก์ชันด้วยพอยน์เตอร์ของฟังก์ชันและบอกสิ่งเหล่านี้เรียกว่าการเรียกกลับ
  • ทีนี้คำถามก็คือว่าทำไมทุกสิ่งที่ยุ่งยากในการเรียกฟังก์ชั่นบางอย่าง? ประโยชน์คืออะไร เช่นเดียวกับพอยน์เตอร์ข้อมูลตัวชี้ฟังก์ชันหรือที่เรียกว่าการเรียกกลับมีข้อดีกว่าการใช้ตัวระบุปกติ
  • สิ่งแรกคือตัวระบุฟังก์ชันหรือชื่อฟังก์ชันไม่สามารถใช้เป็นข้อมูลปกติได้ ฉันหมายความว่าคุณไม่สามารถสร้างโครงสร้างข้อมูลด้วยฟังก์ชั่น (เช่นอาร์เรย์หรือรายการฟังก์ชันที่เชื่อมโยง) แต่ด้วยการโทรกลับคุณสามารถสร้างอาร์เรย์รายการที่เชื่อมโยงหรือใช้กับข้อมูลอื่น ๆ เช่นในพจนานุกรมของคู่คีย์ - ค่าหรือต้นไม้หรือสิ่งอื่นใด นี่คือผลประโยชน์ที่มีประสิทธิภาพ และผลประโยชน์อื่น ๆ คือลูกของอันนี้
  • การใช้งานการเรียกกลับที่พบบ่อยที่สุดจะเห็นได้ในการเขียนโปรแกรมควบคุมเหตุการณ์ ที่หนึ่งหรือมากกว่าหนึ่งฟังก์ชั่นจะดำเนินการตามสัญญาณที่เข้ามา ด้วยการโทรกลับพจนานุกรมสามารถรักษาแผนที่สัญญาณด้วยการโทรกลับ จากนั้นความละเอียดของสัญญาณอินพุตและการประมวลผลของรหัสที่สอดคล้องกันจะง่ายขึ้นมาก
  • การใช้งานการเรียกกลับที่สองในใจของฉันคือฟังก์ชันลำดับที่สูงขึ้น ฟังก์ชั่นที่ใช้ฟังก์ชั่นอื่น ๆ เป็นอาร์กิวเมนต์ที่ป้อนเข้า และในการส่งฟังก์ชั่นเป็นอาร์กิวเมนต์เราต้องมีการเรียกกลับ ตัวอย่างอาจเป็นฟังก์ชั่นที่รับอาเรย์และโทรกลับ จากนั้นจะดำเนินการติดต่อกลับในแต่ละรายการของอาร์เรย์และส่งคืนผลลัพธ์ในอาร์เรย์อื่น หากเราผ่านฟังก์ชั่นการโทรกลับเป็นสองเท่าเราจะได้รับอาร์เรย์มูลค่าสองเท่า ถ้าเราผ่านการเรียกกลับกำลังสองเราจะได้กำลังสอง สำหรับสแควร์รูทเพียงส่งการติดต่อกลับที่เหมาะสม สิ่งนี้ไม่สามารถทำได้ด้วยฟังก์ชั่นปกติ

อาจมีหลายสิ่งหลายอย่าง เกี่ยวข้องกับนักเรียนและพวกเขาจะค้นพบ หวังว่านี่จะช่วยได้


1
คำตอบของฉันที่เกี่ยวข้องกับหัวข้อนี้ใน programmers.SE programmers.stackexchange.com/a/75449/963
Gulshan

3

ในภาษาอังกฤษธรรมดาการติดต่อกลับเป็นสัญญา Joe, Jane, David และ Samantha แบ่งปันเวรเพื่อทำงาน โจกำลังขับรถวันนี้ Jane, David และ Samantha มีสองตัวเลือก:

  1. ตรวจสอบหน้าต่างทุก ๆ 5 นาทีเพื่อดูว่า Joe ออกหรือไม่
  2. ทำสิ่งที่พวกเขาทำต่อไปจนกว่าโจกริ่งประตู

ตัวเลือกที่ 1: นี่เป็นเหมือนตัวอย่างการสำรวจที่ Jane จะติดอยู่ในการตรวจสอบ "ลูป" ถ้าโจอยู่ข้างนอก เจนไม่สามารถทำสิ่งใดได้ในเวลาเดียวกัน

ตัวเลือก 2: นี่คือตัวอย่างการเรียกกลับ เจนบอกให้โจสั่นกระดิ่งเมื่อเขาออกไปข้างนอก เธอให้เขา "ฟังก์ชั่น" เพื่อกดกริ่งประตู โจไม่จำเป็นต้องรู้ว่ากระดิ่งประตูทำงานอย่างไรหรืออยู่ที่ไหนเขาแค่ต้องการเรียกฟังก์ชั่นนั้นเช่นกดกริ่งที่ประตูเมื่อเขาอยู่ที่นั่น

การโทรกลับถูกขับเคลื่อนโดย "กิจกรรม" ในตัวอย่างนี้ "เหตุการณ์" คือการมาถึงของโจ ในอาแจ็กซ์เช่นเหตุการณ์อาจเป็น "ความสำเร็จ" หรือ "ความล้มเหลว" ของการร้องขอแบบอะซิงโครนัสและแต่ละแบบสามารถมีการโทรกลับที่เหมือนกันหรือต่างกัน

ในแง่ของการใช้งานจาวาสคริปต์และการโทรกลับ เราต้องเข้าใจ "การปิด" และบริบทของแอปพลิเคชันด้วย สิ่งนี้หมายถึงอะไรสามารถสับสนนักพัฒนา JavaScript ได้อย่างง่ายดาย ในตัวอย่างนี้ภายใน "ring_the_door_bell ()" วิธีการ / การโทรกลับอาจมีวิธีการอื่นที่แต่ละคนต้องทำตามขั้นตอนการทำงานในตอนเช้า "ปิดทีวี()". เราต้องการให้ "นี่" อ้างถึงวัตถุ "Jane" หรือวัตถุ "David" เพื่อให้แต่ละคนสามารถตั้งค่าสิ่งที่พวกเขาต้องทำก่อนที่ Joe จะหยิบมันขึ้นมา นี่คือจุดที่การตั้งค่าการติดต่อกลับด้วย Joe ต้องใช้วิธีการ parodying เพื่อให้ "นี่" อ้างอิงถึงวัตถุที่ถูกต้อง

หวังว่าจะช่วย!


3

การติดต่อกลับเป็นซองจดหมายที่ประทับตราด้วยตนเอง เมื่อคุณเรียกใช้ฟังก์ชันนั่นก็เหมือนกับการส่งจดหมาย หากคุณต้องการให้ฟังก์ชันนั้นเรียกใช้ฟังก์ชันอื่นคุณต้องระบุข้อมูลนั้นในรูปแบบของการอ้างอิงหรือที่อยู่


3

ฉันคิดว่ามันค่อนข้างง่ายที่จะอธิบาย

เมื่อโทรกลับครั้งแรกเป็นเพียงฟังก์ชั่นธรรมดา
และยิ่งไปกว่านั้นคือเราเรียกฟังก์ชันนี้ (เรียกมันว่า A) จากภายในฟังก์ชันอื่น (เรียกมันว่า B)

มหัศจรรย์เกี่ยวกับเรื่องนี้ก็คือว่าผมตัดสินใจที่ฟังก์ชั่นควรจะเรียกว่าฟังก์ชั่นจากภายนอกบี

ในขณะที่ฉันเขียนฟังก์ชัน BI ไม่รู้ว่าควรเรียกใช้ฟังก์ชันการโทรกลับแบบใด ในเวลาที่ฉันเรียกใช้ฟังก์ชัน BI บอกให้ฟังก์ชั่นนี้เรียกใช้ฟังก์ชัน A นั่นคือทั้งหมด


3

ฟังก์ชั่นโทรกลับคืออะไร?

คำตอบง่ายๆสำหรับคำถามแรกนี้คือฟังก์ชันการเรียกกลับเป็นฟังก์ชันที่เรียกใช้ผ่านตัวชี้ฟังก์ชัน หากคุณผ่านตัวชี้ (ที่อยู่) ของฟังก์ชั่นเป็นอาร์กิวเมนต์ไปยังอีกเมื่อตัวชี้นั้นจะใช้ในการเรียกฟังก์ชั่นมันจะชี้ไปที่มันจะมีการกล่าวว่าการโทรกลับจะทำ

ฟังก์ชั่นการโทรกลับหายาก แต่บางครั้งมันก็มีประโยชน์มาก โดยเฉพาะอย่างยิ่งเมื่อคุณออกแบบห้องสมุด ฟังก์ชั่นการโทรกลับเป็นเหมือนการขอให้ผู้ใช้ของคุณให้ชื่อฟังก์ชั่นและคุณจะเรียกฟังก์ชั่นนั้นภายใต้เงื่อนไขที่แน่นอน

ตัวอย่างเช่นคุณเขียนตัวจับเวลาการโทรกลับ จะช่วยให้คุณระบุระยะเวลาและฟังก์ชั่นการโทรและฟังก์ชั่นจะโทรกลับตามนั้น “ Run myfunction () ทุก ๆ 10 วินาทีเป็นเวลา 5 ครั้ง”

หรือคุณสามารถสร้างไดเรกทอรีฟังก์ชันส่งรายการชื่อฟังก์ชั่นและขอให้ห้องสมุดติดต่อกลับ “ การโทรกลับสำเร็จ () หากสำเร็จโทรกลับล้มเหลว () หากล้มเหลว”

ให้ดูตัวอย่างตัวชี้ฟังก์ชันอย่างง่าย

void cbfunc()
{
     printf("called");
}

 int main ()
 {
                   /* function pointer */ 
      void (*callback)(void); 
                   /* point to your callback function */ 
      callback=(void *)cbfunc; 
                   /* perform callback */
      callback();
      return 0; 
}

วิธีการส่งผ่านข้อโต้แย้งไปยังฟังก์ชั่นการโทรกลับ?

สังเกตว่าตัวชี้ฟังก์ชั่นที่จะใช้โทรกลับใช้ใน void * ซึ่งบ่งชี้ว่าสามารถใช้กับตัวแปรชนิดใดก็ได้รวมถึงโครงสร้าง ดังนั้นคุณสามารถผ่านหลายอาร์กิวเมนต์ตามโครงสร้าง

typedef struct myst
{
     int a;
     char b[10];
}myst;

void cbfunc(myst *mt) 
{
     fprintf(stdout,"called %d %s.",mt->a,mt->b); 
}

int main() 
{
       /* func pointer */
    void (*callback)(void *);       //param
     myst m;
     m.a=10;
     strcpy(m.b,"123");       
     callback = (void*)cbfunc;    /* point to callback function */
     callback(&m);                /* perform callback and pass in the param */
     return 0;   
}

2

การเรียกกลับเป็นวิธีที่มีกำหนดที่จะดำเนินการเมื่อตรงตามเงื่อนไข

ตัวอย่าง "โลกแห่งความจริง" คือร้านวิดีโอเกมในพื้นที่ คุณกำลังรอ Half-Life 3 แทนที่จะไปที่ร้านทุกวันเพื่อดูว่ามันมีอยู่หรือไม่คุณลงทะเบียนอีเมลของคุณในรายการเพื่อรับการแจ้งเตือนเมื่อเกมพร้อมใช้งาน อีเมลดังกล่าวจะกลายเป็น "การติดต่อกลับ" ของคุณและเงื่อนไขที่ต้องทำคือความพร้อมของเกม

ตัวอย่าง "โปรแกรมเมอร์" คือหน้าเว็บที่คุณต้องการดำเนินการเมื่อมีการคลิกปุ่ม คุณลงทะเบียนวิธีการโทรกลับสำหรับปุ่มและทำงานอื่น ๆ ต่อไป เมื่อ / ถ้าผู้ใช้กดปุ่มเบราว์เซอร์จะดูรายการการเรียกกลับสำหรับเหตุการณ์นั้นและเรียกวิธีการของคุณ

การเรียกกลับเป็นวิธีจัดการเหตุการณ์แบบอะซิงโครนัส คุณไม่มีทางรู้ว่าจะทำการโทรกลับเมื่อใดหรือจะดำเนินการใด ๆ ข้อดีคือมันช่วยให้โปรแกรมและรอบการทำงานของ CPU ของคุณทำงานได้อย่างเต็มที่ในขณะที่รอการตอบกลับ


การพูดว่า "กำหนด" อาจทำให้เกิดความสับสนได้ที่นี่ การโทรกลับมักใช้ในระบบอะซิงโครนัสและจะไม่มี "ตารางเวลา" แต่เป็น "เหตุการณ์" แทนซึ่งจะกระตุ้นให้มีการดำเนินการติดต่อกลับ
Deven Phillips

2

ธรรมดาและเรียบง่าย: การเรียกกลับเป็นฟังก์ชั่นที่คุณมอบให้กับฟังก์ชั่นอื่นเพื่อที่จะสามารถเรียกมันได้

โดยปกติจะเรียกว่าเมื่อการดำเนินการบางอย่างเสร็จสมบูรณ์ เนื่องจากคุณสร้างการเรียกกลับก่อนที่จะให้ฟังก์ชันอื่นคุณสามารถเริ่มต้นได้ด้วยข้อมูลบริบทจากไซต์การโทร นั่นคือสาเหตุที่ชื่อการโทร * ย้อนกลับ * - ฟังก์ชั่นแรกโทรกลับสู่บริบทจากที่มันถูกเรียก


2

“ ในการเขียนโปรแกรมคอมพิวเตอร์การเรียกกลับเป็นการอ้างอิงถึงรหัสที่ใช้งานได้หรือส่วนหนึ่งของรหัสที่สามารถเรียกทำงานได้ซึ่งจะถูกส่งเป็นอาร์กิวเมนต์ไปยังรหัสอื่น สิ่งนี้อนุญาตให้เลเยอร์ซอฟต์แวร์ระดับต่ำกว่าเรียกรูทีนย่อย (หรือฟังก์ชัน) ที่กำหนดในเลเยอร์ระดับสูงกว่า” - วิกิพีเดีย

โทรกลับใน C โดยใช้ฟังก์ชั่นตัวชี้

ใน C การเรียกกลับถูกนำไปใช้โดยใช้ Function Pointer ตัวชี้ฟังก์ชั่น - ตามชื่อแนะนำเป็นตัวชี้ไปยังฟังก์ชั่น

ตัวอย่างเช่น int (* ptrFunc) ();

ที่นี่ ptrFunc เป็นตัวชี้ไปยังฟังก์ชั่นที่ไม่มีข้อโต้แย้งและส่งกลับจำนวนเต็ม อย่าลืมใส่ในวงเล็บมิฉะนั้นคอมไพเลอร์จะถือว่า ptrFunc เป็นชื่อฟังก์ชั่นปกติซึ่งไม่ทำอะไรเลยและส่งกลับตัวชี้เป็นจำนวนเต็ม

นี่คือรหัสบางส่วนเพื่อแสดงให้เห็นถึงตัวชี้ฟังก์ชั่น

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

ตอนนี้ให้เราพยายามที่จะเข้าใจแนวคิดของการโทรกลับใน C โดยใช้ตัวชี้ฟังก์ชั่น

โปรแกรมที่สมบูรณ์มีสามไฟล์: callback.c, reg_callback.h และ reg_callback.c

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

ถ้าเรารันโปรแกรมนี้ผลลัพธ์จะเป็น

นี่คือโปรแกรมที่แสดงฟังก์ชันการเรียกกลับภายใน register_callback ด้านใน my_callback ด้านหลังในโปรแกรมหลัก

ฟังก์ชันเลเยอร์ที่สูงกว่าเรียกฟังก์ชันเลเยอร์ที่ต่ำกว่าเป็นการโทรปกติและกลไกการเรียกกลับช่วยให้ฟังก์ชันเลเยอร์ที่ต่ำกว่าเรียกฟังก์ชันเลเยอร์ที่สูงขึ้นผ่านตัวชี้ไปยังฟังก์ชันการเรียกกลับ

การโทรกลับใน Java โดยใช้อินเตอร์เฟส

Java ไม่ได้มีแนวคิดของตัวชี้ฟังก์ชั่นมันใช้กลไกการโทรกลับผ่านกลไกการติดต่อที่นี่แทนที่จะเป็นตัวชี้ฟังก์ชั่นเราประกาศอินเตอร์เฟซที่มีวิธีการซึ่งจะถูกเรียกเมื่อ callee เสร็จสิ้นภารกิจ

ให้ฉันสาธิตผ่านตัวอย่าง:

อินเตอร์เฟสการติดต่อกลับ

public interface Callback
{
    public void notify(Result result);
}

ผู้เรียกหรือระดับที่สูงขึ้น

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

ฟังก์ชัน Callee หรือฟังก์ชันเลเยอร์ที่ต่ำกว่า

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

การโทรกลับโดยใช้รูปแบบ EventListener

  • รายการสินค้า

รูปแบบนี้ใช้เพื่อแจ้งจำนวนผู้สังเกตการณ์ / ผู้ฟังจำนวน 0 ถึง n ว่างานเฉพาะได้เสร็จสิ้นแล้ว

  • รายการสินค้า

ความแตกต่างระหว่างกลไกการโทรกลับและกลไก EventListener / Observer คือในการติดต่อกลับผู้แจ้งเตือนจะแจ้งผู้โทรเพียงคนเดียวในขณะที่ผู้จัดกิจกรรม / ผู้สังเกตการณ์ผู้รับสามารถแจ้งผู้ที่สนใจเหตุการณ์นั้นได้ (การแจ้งเตือนอาจไปยังส่วนอื่น ๆ ของ แอปพลิเคชั่นที่ไม่ได้เรียกใช้งาน

ให้ฉันอธิบายผ่านตัวอย่าง

อินเทอร์เฟซเหตุการณ์

public interface Events {

public void clickEvent();
public void longClickEvent();
}

วิดเจ็ตชั้นเรียน

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

ปุ่มคลาส

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

ช่องทำเครื่องหมายคลาส

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

ชั้นเรียนกิจกรรม

แพ็คเกจ com.som_itsolutions.training.java.exampleeventlistener;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

ชั้นอื่น ๆ

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

ชั้นเรียนหลัก

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

ดังที่คุณเห็นจากโค้ดด้านบนเรามีอินเทอร์เฟซที่เรียกว่าเหตุการณ์ซึ่งโดยทั่วไปจะแสดงรายการเหตุการณ์ทั้งหมดที่อาจเกิดขึ้นสำหรับแอปพลิเคชันของเรา คลาส Widget เป็นคลาสพื้นฐานสำหรับส่วนประกอบ UI ทั้งหมดเช่นปุ่ม, ช่องทำเครื่องหมาย องค์ประกอบ UI เหล่านี้เป็นวัตถุที่รับเหตุการณ์จากรหัสเฟรมเวิร์ก คลาสวิดเจ็ตใช้อินเทอร์เฟซเหตุการณ์และมีอินเทอร์เฟซซ้อนกันสองรายการ ได้แก่ OnClickEventListener & OnLongClickEventListener

อินเทอร์เฟซสองเหล่านี้มีหน้าที่รับผิดชอบในการรับฟังเหตุการณ์ที่อาจเกิดขึ้นกับส่วนประกอบ UI ที่ได้รับจาก Widget เช่นปุ่มหรือช่องทำเครื่องหมาย ดังนั้นหากเราเปรียบเทียบตัวอย่างนี้กับตัวอย่างการติดต่อกลับก่อนหน้านี้โดยใช้ Java Interface ทั้งสองอินเตอร์เฟสนี้จะทำงานเป็นอินเตอร์เฟสการติดต่อกลับ ดังนั้นรหัสระดับที่สูงขึ้น (กิจกรรมที่นี่) จะใช้อินเทอร์เฟซทั้งสองนี้ และเมื่อใดก็ตามที่มีเหตุการณ์เกิดขึ้นกับวิดเจ็ตรหัสระดับที่สูงกว่า (หรือวิธีการของอินเทอร์เฟซเหล่านี้ถูกนำไปใช้ในรหัสระดับที่สูงขึ้น

ตอนนี้ให้ฉันพูดถึงความแตกต่างพื้นฐานระหว่างรูปแบบการโทรกลับและ Eventlistener ดังที่เราได้กล่าวไปแล้วว่าการใช้การโทรกลับผู้ใช้สามารถแจ้งเตือนได้เพียงผู้โทรเดียว แต่ในกรณีของรูปแบบ EventListener ส่วนอื่น ๆ หรือคลาสของแอปพลิเคชันสามารถลงทะเบียนสำหรับเหตุการณ์ที่อาจเกิดขึ้นในปุ่มหรือช่องทำเครื่องหมาย ตัวอย่างของคลาสประเภทนี้คือ OtherClass หากคุณเห็นรหัสของ OtherClass คุณจะพบว่ามันได้ลงทะเบียนตัวเองเป็นผู้ฟังของ ClickEvent ที่อาจเกิดขึ้นในปุ่มที่กำหนดไว้ในกิจกรรม ส่วนที่น่าสนใจคือนอกเหนือจากกิจกรรม (ตัวเรียก), OtherClass นี้จะได้รับแจ้งเมื่อใดก็ตามที่มีเหตุการณ์การคลิกเกิดขึ้นบนปุ่ม


1

การเรียกกลับช่วยให้คุณสามารถแทรกรหัสของคุณเองลงในบล็อกของรหัสอื่นที่จะดำเนินการในเวลาอื่นซึ่งจะปรับเปลี่ยนหรือเพิ่มลักษณะการทำงานของบล็อกรหัสอื่นที่เหมาะสมกับความต้องการของคุณ คุณได้รับความยืดหยุ่นและปรับแต่งได้ในขณะที่สามารถมีรหัสที่สามารถบำรุงรักษาได้มากขึ้น

hardcode น้อยลง = ง่ายต่อการดูแลและเปลี่ยนแปลง = เวลาน้อยลง = มูลค่าทางธุรกิจมากขึ้น = ยอดเยี่ยม

ตัวอย่างเช่นในจาวาสคริปต์โดยใช้ Underscore.js คุณสามารถค้นหาองค์ประกอบทั้งหมดได้ในอาร์เรย์ดังนี้

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

ตัวอย่างความอนุเคราะห์จาก Underscore.js: http://documentcloud.github.com/underscore/#filter


1

[แก้ไข] เมื่อเรามีสองฟังก์ชั่นบอกว่าfunctionA และ functionBถ้าfunctionAขึ้นอยู่กับfunctionB

ดังนั้นเราจึงเรียกใช้ functionBเป็นฟังก์ชันการเรียกกลับซึ่งใช้กันอย่างแพร่หลายในกรอบงาน Spring

ฟังก์ชั่นการโทรกลับตัวอย่างวิกิพีเดีย


1

ลองนึกถึงวิธีการหนึ่งในการมอบหมายงานให้ผู้ร่วมงาน ภารกิจง่าย ๆ อาจเป็นดังต่อไปนี้:

Solve these equations:
x + 2 = y
2 * x = 3 * y

เพื่อนร่วมงานของคุณขยันทำคณิตศาสตร์และให้ผลลัพธ์ต่อไปนี้:

x = -6
y = -4

แต่เพื่อนร่วมงานของคุณมีปัญหาเขาไม่เข้าใจสัญลักษณ์เช่น^เสมอ แต่เขาเข้าใจคำอธิบายของพวกเขา exponentเช่น ทุกครั้งที่เขาพบหนึ่งในสิ่งเหล่านี้คุณจะได้รับสิ่งต่อไปนี้:

I don't understand "^"

สิ่งนี้ต้องการให้คุณเขียนคำแนะนำทั้งหมดของคุณอีกครั้งหลังจากอธิบายว่าตัวละครนั้นมีความหมายอย่างไรต่อผู้ร่วมงานของคุณและเขาก็จำไม่ได้ว่าเกิดอะไรขึ้นระหว่างคำถาม และเขาก็มีปัญหาในการจำเคล็ดลับของคุณเช่นถามฉัน เขามักจะทำตามคำแนะนำของคุณเท่าที่จะทำได้

คุณคิดถึงวิธีแก้ปัญหาคุณเพียงเพิ่มคำแนะนำต่อไปนี้ลงในคำแนะนำทั้งหมด:

If you have any questions about symbols, call me at extension 1234 and I will tell you its name.

ตอนนี้เมื่อใดก็ตามที่เขามีปัญหาเขาโทรหาคุณและถามแทนที่จะให้การตอบสนองที่ไม่ดีและทำให้กระบวนการรีสตาร์ท


0

สิ่งนี้ในแง่ของการดาวน์โหลดเว็บเพจ:

โปรแกรมของคุณทำงานบนโทรศัพท์มือถือและมีการร้องขอหน้าเว็บhttp://www.google.com หากคุณเขียนโปรแกรมของคุณพร้อมกันฟังก์ชันที่คุณเขียนเพื่อดาวน์โหลดข้อมูลจะทำงานอย่างต่อเนื่องจนกว่าข้อมูลทั้งหมดจะถูกดาวน์โหลด ซึ่งหมายความว่า UI ของคุณจะไม่รีเฟรชและโดยทั่วไปจะปรากฏเป็นน้ำแข็ง หากคุณเขียนโปรแกรมของคุณโดยใช้การเรียกกลับคุณขอข้อมูลและพูดว่า "ดำเนินการฟังก์ชั่นนี้เมื่อคุณทำเสร็จแล้ว" สิ่งนี้ทำให้ UI ยังคงอนุญาตให้ผู้ใช้โต้ตอบในขณะที่ไฟล์กำลังดาวน์โหลด เมื่อเว็บเพจดาวน์โหลดเสร็จแล้วฟังก์ชันผลลัพธ์ (การเรียกกลับ) ของคุณจะถูกเรียกใช้และคุณสามารถจัดการข้อมูลได้

โดยทั่วไปจะช่วยให้คุณสามารถร้องขอบางสิ่งและดำเนินการต่อในขณะที่รอผล เมื่อผลลัพธ์กลับมาถึงคุณผ่านฟังก์ชั่นการโทรกลับคุณสามารถรับการดำเนินการที่ค้างไว้ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.