Lời hứa không bao giờ được giải quyết có gây rò rỉ bộ nhớ không?


91

Tôi có một Promise. Tôi đã tạo nó để hủy yêu cầu AJAX nếu cần. Nhưng vì tôi không cần phải hủy AJAX đó, nên tôi chưa bao giờ giải quyết nó và AJAX đã hoàn thành thành công.

Một đoạn mã đơn giản:

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?

Những lời hứa không bao giờ được giải quyết như vậy có gây rò rỉ bộ nhớ không? Bạn có lời khuyên nào về cách quản lý Promisevòng đời không?


4
Một lời hứa "không bao giờ được giải quyết" vẫn có thể bị "từ chối". Từ bạn đang tìm là "chưa được thực hiện".
Steven Vachon

$ http là một ví dụ thú vị vì cuối cùng một yêu cầu HTTP sẽ hết thời gian chờ (hoặc nói cách khác là mang lại phản hồi lỗi), nếu máy khách không thể truy cập máy chủ, bất kể lời hứa được chuyển đến đối số 'timeout'.
ryanwebjackson

Câu trả lời:


144

Vâng, tôi cho rằng bạn không giữ một tham chiếu rõ ràng về nó vì điều đó sẽ buộc nó phải được phân bổ.

Thử nghiệm đơn giản nhất mà tôi có thể nghĩ ra là thực sự phân bổ rất nhiều lời hứa và không giải quyết được chúng:

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

Và sau đó xem chính đống. Như chúng ta có thể thấy trong các công cụ cấu hình của Chrome, điều này tích lũy bộ nhớ cần thiết để phân bổ 100 lời hứa và sau đó chỉ "ở đó" ở mức dưới 15 megabyte cho toàn bộ trang JSFIddle

nhập mô tả hình ảnh ở đây

Từ phía bên kia, nếu chúng ta nhìn vào $qmã nguồn

Chúng ta có thể thấy rằng không có tham chiếu từ điểm toàn cục đến bất kỳ lời hứa cụ thể nào mà chỉ từ một lời hứa đến các lệnh gọi lại của nó. Mã rất dễ đọc và rõ ràng. Hãy xem điều gì sẽ xảy ra nếu bạn có tham chiếu từ callback đến promise.

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);

nhập mô tả hình ảnh ở đây

Vì vậy, sau khi phân bổ ban đầu - có vẻ như nó cũng có thể xử lý điều đó :)

Chúng ta cũng có thể thấy một số mẫu thú vị của GC nếu chúng ta để ví dụ cuối cùng của anh ấy chạy thêm vài phút nữa. Chúng ta có thể thấy rằng phải mất một lúc - nhưng nó có thể làm sạch các lệnh gọi lại.

nhập mô tả hình ảnh ở đây

Tóm lại - ít nhất là trong các trình duyệt hiện đại - bạn không phải lo lắng về những lời hứa chưa được giải quyết miễn là bạn không có tham chiếu bên ngoài về chúng


7
Điều này không có nghĩa là nếu một lời hứa mất quá nhiều thời gian để giải quyết (nhưng cuối cùng sẽ được giải quyết), nó có nguy cơ bị GC?
w.brian

5
@ w.brian trừ khi bạn gán nó ở đâu đó - ví dụ: cho một biến: var b = $http.get(...)hoặc thêm một lệnh gọi lại vào nó. Điều đó cũng có một tham chiếu đến nó. Nếu điều gì đó giải quyết nó (như bạn đã nói - quá lâu để giải quyết vẫn có nghĩa là giải quyết) - nó phải có một tham chiếu đến nó. Vì vậy, có - nó sẽ không được GC'd
Benjamin Gruenbaum

3
Gotcha, đó là những gì tôi nghĩ. Vì vậy, câu hỏi đặt ra là "Những lời hứa không bao giờ được giải quyết có gây ra rò rỉ bộ nhớ không?" Câu trả lời, đối với trường hợp sử dụng phổ biến, nơi một cuộc gọi lại được chuyển đến lời hứa, là có. Dòng này trong câu trả lời của bạn dường như mâu thuẫn với điều đó: "Chúng tôi cũng có thể thấy một số mẫu GC thú vị nếu chúng tôi để ví dụ cuối cùng của anh ấy chạy thêm vài phút nữa. Chúng tôi có thể thấy rằng phải mất một lúc - nhưng nó có thể xóa các lệnh gọi lại. " Xin lỗi nếu tôi là người khó tính và không kén chọn, tôi chỉ đang cố gắng đảm bảo rằng tôi hiểu điều này.
w.brian

1
Điều đó dường như không có ý nghĩa đối với tôi. Nếu tôi đã tạo 100.000 lời hứa rằng console.log () 'đã chỉnh sửa một số dòng. Tôi muốn 100.000 đó ghi lại những dòng đó nếu chúng đột ngột giải quyết bằng một phép thuật nào đó. Hoặc bạn đang nói rằng trình duyệt sẽ biết rằng điều này sẽ không bao giờ giải quyết được, vì cả tôi và trình duyệt thực tế đều không có bất kỳ tham chiếu nào đến nó (không có gì ảnh hưởng đến nó) - vậy làm sao điều đó có thể trở thành sự thật? (hmm, tôi có thể thấy rằng có thể là true)
odinho - Velmont

8
Có một số sự thật trong những nhận xét này và một số sai lệch, vì vậy hãy để tôi làm rõ: Một lời hứa với những người xử lý kèm theo thể đủ điều kiện để thu gom rác. Một lời hứa được giữ nguyên (không đủ điều kiện GC) nếu bất kỳ điều nào sau đây là đúng: (1) có tham chiếu đến đối tượng lời hứa, (2) có tham chiếu đến trạng thái "hoãn lại" của lời hứa (đối tượng / chức năng bạn sử dụng để giải quyết / từ chối nó). Ngoài điều này, lời hứa đủ điều kiện cho GC. (Nếu ai có lời hứa và không ai có thể thay đổi trạng thái của nó, là những gì mục đích của nó nữa, dù sao?)
cdhowie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.