ไม่เคยแก้ไขสัญญาทำให้หน่วยความจำรั่ว?


92

ฉันมีPromise. ฉันสร้างมันขึ้นเพื่อยกเลิกคำขอ AJAX หากจำเป็น แต่เนื่องจากฉันไม่จำเป็นต้องยกเลิก AJAX นั้นฉันจึงไม่เคยแก้ไขเลยและ AJAX ก็ทำสำเร็จ

ข้อมูลโค้ดแบบง่าย:

var defer = $q.defer();
$http({url: 'example.com/some/api', timeout: defer.promise}).success(function(data) {
    // do something
});

// Never defer.resolve() because I don't need to cancel that ajax. What happens to this promise after request?

ไม่เคยแก้สัญญาเช่นนั้นทำให้หน่วยความจำรั่วไหล? คุณมีคำแนะนำเกี่ยวกับการจัดการPromiseวงจรชีวิตหรือไม่?


4
คำสัญญาที่ "ไม่เคยแก้ไข" ยังคงสามารถ "ปฏิเสธ" ได้ คำที่คุณกำลังมองหาคือ "ไม่ได้ผล"
Steven Vachon

$ http เป็นตัวอย่างที่น่าสนใจเพราะในที่สุดคำขอ HTTP จะหมดเวลา (หรือตอบสนองข้อผิดพลาด) หากไคลเอนต์ไม่สามารถเข้าถึงเซิร์ฟเวอร์ได้ไม่ว่าสัญญาจะส่งไปยังอาร์กิวเมนต์ "หมดเวลา" ก็ตาม
ryanwebjackson

คำตอบ:


146

ฉันสมมติว่าคุณไม่ได้อ้างอิงอย่างชัดเจนเนื่องจากจะบังคับให้จัดสรรต่อไป

การทดสอบที่ง่ายที่สุดที่ฉันคิดได้คือการจัดสรรสัญญาจำนวนมากและไม่สามารถแก้ไขได้:

var $q = angular.injector(["ng"]).get("$q");
setInterval(function () {
    for (var i = 0; i < 100; i++) {
        var $d = $q.defer();
        $d.promise;
    }
}, 10);

แล้วดูกองเอง. ดังที่เราเห็นในเครื่องมือสร้างโปรไฟล์ Chrome สิ่งนี้จะสะสมหน่วยความจำที่จำเป็นเพื่อจัดสรรสัญญา 100 สัญญาจากนั้นก็ "อยู่ที่นั่น" ที่น้อยกว่า 15 เมกะไบต์สำหรับทั้งหน้า JSFIddle

ป้อนคำอธิบายภาพที่นี่

จากอีกด้านหนึ่งถ้าเราดู$qซอร์สโค้ด

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

var $q = angular.injector(["ng"]).get("$q");
console.log($q);
setInterval(function () {
    for (var i = 0; i < 10; i++) {
        var $d = $q.defer();
        (function ($d) { // loop closure thing
            $d.promise.then(function () {
                console.log($d);
            });
        })($d);
    }
}, 10);

ป้อนคำอธิบายภาพที่นี่

หลังจากการจัดสรรครั้งแรกดูเหมือนว่าจะสามารถจัดการได้เช่นกัน :)

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

ป้อนคำอธิบายภาพที่นี่

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


8
นี่ไม่ได้หมายความว่าหากคำสัญญาใช้เวลานานเกินไปในการแก้ไข (แต่จะแก้ไขได้ในที่สุด ) ก็เสี่ยงต่อการเป็น GC หรือไม่?
w.brian

6
@ w.brian เว้นแต่คุณจะกำหนดไว้ที่ใดที่หนึ่ง - ตัวอย่างเช่นให้กับตัวแปร: var b = $http.get(...)หรือเพิ่มการเรียกกลับเข้าไป นอกจากนี้ยังมีการอ้างอิงถึง หากมีบางอย่างแก้ไขได้ (เช่นที่คุณพูด - นานเกินไปที่จะแก้ไขยังคงหมายถึงการแก้ไข) - จะต้องมีการอ้างอิงถึงมัน ใช่ - มันจะไม่ใช่ GC'd
Benjamin Gruenbaum

3
Gotcha นั่นคือสิ่งที่ฉันคิด คำถามคือ "คำสัญญาที่ไม่เคยแก้ไขจะทำให้หน่วยความจำรั่วหรือไม่" คำตอบสำหรับกรณีการใช้งานทั่วไปที่มีการส่งการโทรกลับไปยังสัญญาคือใช่ บรรทัดนี้ในคำตอบของคุณดูเหมือนจะขัดแย้งว่า: "นอกจากนี้เรายังสามารถเห็นรูปแบบที่น่าสนใจของ GC ได้หากเราปล่อยให้ตัวอย่างสุดท้ายของเขาดำเนินต่อไปอีกสองสามนาทีเราจะเห็นว่าต้องใช้เวลาสักครู่ แต่ก็สามารถล้างการเรียกกลับได้ " ขออภัยหากฉันเป็นคนขี้อวดและจู้จี้จุกจิกฉันแค่พยายามทำให้แน่ใจว่าฉันเข้าใจสิ่งนี้
w.brian

1
นั่นดูเหมือนจะไม่สมเหตุสมผลสำหรับฉัน ถ้าฉันสร้าง 100.000 สัญญาว่า console.log () 'แก้ไขบางบรรทัด ฉันต้องการให้ 100.000 เหล่านั้นบันทึกเส้นเหล่านั้นหากพวกเขาแก้ไขด้วยเวทมนตร์ในทันใด หรือคุณกำลังบอกว่าเบราว์เซอร์จะรู้ว่าสิ่งนี้จะไม่มีวันแก้ไขได้เนื่องจากทั้งฉันและเบราว์เซอร์จริงไม่มีการอ้างอิงใด ๆ (ไม่มีผลกระทบใด ๆ ) - แล้วมันจะเป็นจริงได้อย่างไร? (อืมฉันเห็นว่าอาจเป็นเรื่องจริง)
odinho - Velmont

9
มีความจริงบางอย่างในความคิดเห็นเหล่านี้และบางส่วนที่ทำให้เข้าใจผิดดังนั้นขอให้ฉันชี้แจง: สัญญากับตัวจัดการที่แนบมาอาจมีสิทธิ์ได้รับการเก็บขยะ คำสัญญาจะยังคงมีชีวิตอยู่ (ไม่มีสิทธิ์ GC) หากข้อใดต่อไปนี้เป็นจริง: (1) มีการอ้างอิงถึงวัตถุคำสัญญา (2) มีการอ้างอิงถึงสถานะ "รอการตัดบัญชี" ของสัญญา (วัตถุ / ฟังก์ชันที่คุณใช้เพื่อแก้ไข / ปฏิเสธ) นอกเหนือจากนี้สัญญาดังกล่าวมีสิทธิ์สำหรับ GC (ถ้าไม่มีใครมีสัญญาและไม่มีใครสามารถเปลี่ยนสถานะได้จุดประสงค์ของมันคืออะไรอีกต่อไป?)
cdhowie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.