การเรียกกลับรอตัดบัญชีคืออะไร


15

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

ฉันพยายามที่จะเข้าใจการโทรกลับรอการตัดบัญชีแม้หลังจาก googling

ใครช่วยอธิบายง่ายๆได้ไหม ฉันเขียนโปรแกรมใน Ruby แต่รู้ C / C ++ นิดหน่อย แต่ที่สำคัญที่สุดฉันเป็นโปรแกรมเมอร์ภาษาแอสเซมบลีที่มีประสบการณ์ ดังนั้นฉันสงสัยว่ามันเป็นบิตของที่อยู่ติดต่อกลับที่ได้รับป๊อปหรือไม่ ฉันหวังว่าจะได้เรียนรู้ jquery หรือ node.js และการเรียกกลับที่เลื่อนออกไปเหล่านี้ดูเหมือนจะเป็นสิ่งสำคัญสำหรับทั้งสองคน ฉันเข้าใจหลักการทำเกลียวขั้นพื้นฐาน (แม้ว่าวัตถุ mutex ทำให้ฉันเจ็บหัว)


คุณหมายถึงDeferredวัตถุของ jQuery หรือไม่? สิ่งนี้เกี่ยวกับ Node.js หรือไม่?
bfavaretto

1
ไม่ฉันหมายถึงโดยทั่วไป แม้ว่าฉันจะต้องการเรียนรู้ jquery และอาจเป็น node.js แต่ฉันรู้สึกว่าฉันต้องได้รับการจัดการกับสิ่งที่โทรกลับรอการตัดบัญชีเป็นครั้งแรก ฉันอ่านบทความวิกิพีเดียเกี่ยวกับการโทรกลับ แต่ฉันไม่สามารถเข้าใจการโทรกลับที่เลื่อนเวลาออกไปซึ่งดูเหมือนจะเป็นกรอบความคิดในการดำเนินการแบบอะซิงโครนัสซึ่งจะเกี่ยวข้องกับภาษาเหล่านี้ที่ใช้งาน


1
ฉันขอแนวคิดเกี่ยวกับการโทรกลับรอการตัดบัญชีซึ่งตรงข้ามกับการดำเนินการของพวกเขา - ขออภัยถ้าฉันไม่ได้ทำให้ชัดเจนขึ้น ฉันยกตัวอย่างภาษาเพื่ออธิบายแนวคิดที่ฉันพยายามอธิบายและพื้นหลังการเขียนโปรแกรมของฉันเพื่อให้ผู้คนรู้วิธีตอบคำถาม ขอบคุณมากสำหรับคำตอบจนถึงตอนนี้ - ฉันไปถึงที่นั่น!
tentimes

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

คำตอบ:


4

ตามคำขอนี่คือความคิดเห็นที่นำเสนอเป็นคำตอบ:


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

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

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

เนื้อหาส่วนใหญ่เป็น async ใน node.js แต่ในเบราว์เซอร์เช่น jQuery เนื้อหาส่วนใหญ่จะเป็นแบบซิงโครนัส (ยกเว้นเห็นได้ชัดสำหรับคำขอ AJAX) เนื่องจากฟังก์ชั่นเฟิร์สคลาสมีประโยชน์อย่างมากใน JavaScript (โดยเฉพาะอย่างยิ่งเนื่องจากการสนับสนุนการปิดที่ยอดเยี่ยม) การเรียกกลับจึงถูกใช้ทุกที่ในเบราว์เซอร์ด้วยเช่นกัน แต่พวกมันไม่ใช่ "รอการตัดบัญชี" คุณ แต่หลังจากนั้นโดยฟังก์ชั่นที่คุณโทร)

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


8

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

ตอนนี้เราสามารถดูว่า Deferred Object คืออะไร นำตัวอย่างข้อมูลด้านล่างเป็นตัวอย่าง

var deferred = $.Deferred();
var promise = deferred.promise();

สิ่งที่เรามีตอนนี้คือวัตถุรอการตัดบัญชีและวัตถุสัญญาของวัตถุรอการตัดบัญชี วัตถุรอตัดบัญชีมีทุกวิธีการเช่นเดียวกับวัตถุสัญญา แต่วัตถุสัญญาเพียง แต่มีวิธีการ.done(), .fail()และที่ใช้ในการเพิ่มการเรียกกลับไปยังวัตถุที่รอการตัดบัญชีสำหรับแต่ละที่เกี่ยวข้อง.always() eventวัตถุรอการตัดบัญชีในมืออื่น ๆ มีวิธีการอื่น ๆ อีกหลายที่สำคัญที่สุดและ.resolve() .reject()เมื่อวิธีการเหล่านี้ถูกเรียกบนวัตถุรอการตัดบัญชีการเรียกกลับทั้งหมดจะถูกเรียก .resolve()fires .done()และ.always()callbacks ขณะที่.reject()เมธอด call .fail()และ.always()callbacks

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

นี่เป็นอีกตัวอย่างหนึ่งที่ฉันใช้:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ$.Deferred()วิธีการของ jQuery และวัตถุที่ถูกเลื่อนเวลาไปที่http://api.jquery.com/category/deferred-object/


นี่อาจจะประเมินค่าไม่ได้เมื่อฉันได้รับรอบหัวของฉันแนวคิดของการโทรกลับรอการตัดบัญชี ขออภัยฉันยังไม่เข้าใจแนวคิดของการโทรกลับที่ถูกเลื่อนออกไป ฉันกำลังมองหาแนวคิดที่อยู่เบื้องหลังมันมากขึ้น เรียงตามแนวความคิดของ Mihia เมื่อฉันได้รับรอบของฉันแล้วบางทีฉันสามารถเข้าใจ js
เวลา

3

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

คำอธิบายที่ดีที่สุดที่ฉันพบคือที่http://www.nodebeginner.org

เฮ้อาจจะยอดเยี่ยมฟังก์ชั่น () โปรดทำสิ่งที่คุณ แต่ฉันด้าย Node.js เดียวจะไม่รอที่นี่จนกว่าคุณจะเสร็จสิ้นฉันจะยังคงรันบรรทัดของรหัสด้านล่างคุณดังนั้นคุณจะโปรด callbackFunction นี้ () ที่นี่และเรียกมันเมื่อคุณทำสิ่งที่มีราคาแพงของคุณเสร็จแล้ว? ขอบคุณ!"

ในตัวอย่างนี้อาจ ExExtensiveFunction เป็น non-blocking (หรือฟังก์ชัน async) ซึ่งหมายความว่าจะไม่ถูกเรียกใช้งานทันที แต่วางไว้ในเหตุการณ์วนรอบที่เรียกว่า เธรด node.js จะทำการประมวลผลต่อไป แต่ในบางเวลามันจะตัดสินใจดำเนินการบางอย่างจากลูปเหตุการณ์ เมื่อมันมาถึง ExExtensiveFunction มันจะเรียกมันและเมื่อ ExpensiveFunction นั้นเสร็จสิ้นการประมวลผลมันก็จะเรียกการเรียกกลับ (เลื่อนออกไป) ที่ส่งผ่านเป็นพารามิเตอร์ให้กับมัน

เป็นตัวอย่างของอาจExExtensiveFunctionคุณสามารถใช้fs.readFile


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

แก้ไขคำตอบบางทีมันอาจชัดเจนกว่านี้

มีประโยชน์มาก แต่ ... ฉันต้องดำเนินการเรียกกลับที่เก็บไว้นี้หรือไม่ สิ่งที่ฉันหมายถึงคือสิ่งที่ประมวลผลรายการนี้ คือ (ตัวอย่าง) หรือไม่ที่ js ยกการเรียกกลับเหล่านี้ในพื้นหลังโดยที่คุณไม่ต้องทำอะไรเลยหรือเป็นเหตุการณ์ที่ทำให้ node.js หรือบางสิ่งบางอย่างเรียกการโทรกลับโดยเฉพาะ ขออภัยฉันได้รับประมาณ 70% ของสิ่งที่คุณพูด แต่ฉันเพียงเล็ก ๆ น้อย ๆ หายไปในส่วนที่เหลือ :)
tentimes

@tentimes - "มันคืออะไรที่กำลังประมวลผลรายการนี้" วัตถุ $ .Deferred () กำลังประมวลผลรายการ เมื่อคุณโทร.resolve()หรือ.reject()บนวัตถุรอการตัดบัญชีเดิมรายการโทรกลับจะถูกเรียก
user400654

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

3

JavaScript มีเธรดเดียวดังนั้นคุณจึงไม่สามารถคิดในแง่ของเธรดที่จะเข้าใจสิ่งนี้ นี่คือตัวอย่างของการโทรกลับทั้งแบบปกติและแบบอะซิงโครนัสโดยใช้ jQuery:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);

ตอนนี้นี่ทำให้ฉันอยู่ที่ไหนสักแห่งขอบคุณ ดังนั้นอะซิงโครนัสจึงตอบสนองต่อเหตุการณ์ที่ฉันได้ติดตั้งด้วย ajax - แค่เอามันออกไปและถ้าเกิดเหตุการณ์ที่เกิดขึ้นการติดต่อกลับของฉันถูกเรียก ฉันคิดว่าฉันได้รับมัน node.js / jquery จะทำบางสิ่งที่คล้ายกับ jquery usnig deferred objectและระบบที่ซับซ้อนในการโต้ตอบกับพวกมันเพื่อทำสิ่งเดียวกัน แต่ใช้วิธีการหรือไม่?
เวลา

1
@tentimes แน่นอน! การเรียกกลับมักจะทำงานเพื่อตอบสนองต่อเหตุการณ์ (แต่เนื่องจาก "การโทรกลับ" ไม่ใช่โครงสร้างภาษา js บางครั้งคำนี้จะใช้ในบริบทอื่น ๆ ) วัตถุที่รอการตัดบัญชี (คำสัญญา) ที่คุณเห็นในคำตอบของเควินนั้นโดยทั่วไปคือน้ำตาลประโยค พวกเขาได้รับ "แก้ไข" หรือ "ปฏิเสธ" เมื่อมีเหตุการณ์บางอย่าง (แบบอะซิงโครนัส) ถูกทริกเกอร์จากนั้นพวกเขาจะเรียกการติดต่อกลับที่เหมาะสม ("เสร็จสิ้น" หรือ "ล้มเหลว" จากนั้น "เสมอ") การใช้พวกมันใน jQuery สามารถทำให้โค้ดอ่านง่ายขึ้นและอนุญาตให้ใช้กลอุบายเพิ่มเติม (เช่นเพิ่มการโทรกลับที่สองได้อย่างง่ายดายหลังจากยิงคำขอ ajax เป็นต้น)
bfavaretto

ทั้งสองเป็นการเรียกกลับแบบอะซิงโครนัส
Raynos

1

Callbacks รอการตัดบัญชี (aka Promices ) ช่วยให้คุณสามารถเขียนโค้ดอะซิงโครนัสตามลำดับโดยไม่มีความเจ็บปวดและปาเก็ตตี้โทรกลับ:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

'เมื่อ' ช่วยให้คุณรอฟังก์ชั่นเพื่อกลับมาขนานและthenสามารถถูกล่ามโซ่ตามลำดับ

One note: jQuery deferreds ! = Promices / Aไวยากรณ์ของพวกเขานั้นแตกต่างกันเล็กน้อย

หนึ่ง: มีบทความที่ดีในหัวข้อมีที่ IEBlogและอื่น ๆ ที่อยู่ในบล็อกสุ่มบางเป็นหนังสือและคำถาม StackOverflow นิยม


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