Có thể tạo "tham chiếu yếu" trong javascript không?


97

Có cách nào trong javascript để tạo một "tham chiếu yếu" đến một đối tượng khác không? Đây là trang wiki mô tả tham chiếu yếu là gì. Đây là một bài viết khác mô tả chúng trong Java. Bất cứ ai có thể nghĩ ra một cách để thực hiện hành vi này trong javascript?


4
Các tham chiếu yếu đang được thảo luận cho ES6. Giữ cho đôi mắt của bạn bị bong tróc.
Ryan Smith

2
* Wiki / thảo luận thông số chính thức tại wiki.ecmascript.org/doku.php?id=strawman:weak_refs , hiện tại là “Sửa đổi lần cuối: 2013/02/02 22:25” * một số thảo luận về thông số kỹ thuật khác tại esdiscuss.org/topic/what -is-the-status-of- thin -reference , hiện là bài đăng cuối cùng “Chủ nhật ngày 3 tháng 3 11:56:05 PST 2013”
Destiny Architect

Trong hầu hết các trường hợp, WR là một nỗ lực để giải quyết Vấn đề trình xử lý chậm , được thảo luận tại đây: [ stackoverflow.com/questions/43758217/… . Nếu câu hỏi đó có một câu trả lời tốt, tôi không nghĩ sẽ cần nhiều WR.
James

Câu trả lời:


39

Không có hỗ trợ ngôn ngữ cho các yếu trong JavaScript. Bạn có thể tự cuộn bằng cách sử dụng đếm tham chiếu thủ công, nhưng đặc biệt không suôn sẻ. Bạn không thể tạo một đối tượng trình bao bọc proxy, vì trong JavaScript, các đối tượng không bao giờ biết khi nào chúng sắp được thu gom.

Vì vậy, 'tham chiếu yếu' của bạn trở thành một khóa (ví dụ: số nguyên) trong một tra cứu đơn giản, với một phương thức bổ sung và xóa tham chiếu và khi không còn tham chiếu được theo dõi thủ công nữa thì mục nhập có thể bị xóa, để lại các tra cứu trong tương lai phím đó để trả về null.

Đây không thực sự là một nhược điểm, nhưng nó có thể giải quyết một số vấn đề tương tự. Nó thường được thực hiện trong các ứng dụng web phức tạp để ngăn rò rỉ bộ nhớ từ các trình duyệt (thường là IE, đặc biệt là các phiên bản cũ hơn) khi có một vòng lặp tham chiếu giữa DOM Node hoặc trình xử lý sự kiện và một đối tượng được liên kết với nó chẳng hạn như một bao đóng. Trong những trường hợp này, một lược đồ đếm tham chiếu đầy đủ thậm chí có thể không cần thiết.


2
Tôi chưa kiểm tra kỹ (hoặc sử dụng) mã, nhưng es-lab có một tập lệnh cung cấp mô phỏng WeakMap cơ bản . Aurora 6 (Mozilla) có triển khai WeakMap không chuẩn .
theazureshadow

2
Với ES6, câu trả lời này không còn đúng nữa. Xem câu trả lời của tôi dưới đây stackoverflow.com/a/28567560/745190
thelastshadow

9
Nó vẫn đúng, vì ES6 WeakMaps không phải là tham chiếu yếu thực sự. WeakMaps chỉ chấp nhận các đối tượng làm khóa và các tham chiếu đến các đối tượng này được lưu giữ yếu. Xem stackoverflow.com/questions/32397729/…
CodeManX

Tôi đã viết một lớp học để mô phỏng một bản đồ yếu và đăng nó ở đây: stackoverflow.com/a/47017206/491553
Ryan Shillington


11

Cập nhật: tháng 9 năm 2019

Hiện vẫn chưa thể sử dụng các tham chiếu yếu, nhưng rất có thể sẽ sớm sử dụng được, vì WeakRefs trong JavaScript là Work In Progress. Chi tiết bên dưới.

Đề nghị

Đề xuất hiện đang ở Giai đoạn 3 có nghĩa là nó có thông số kỹ thuật hoàn chỉnh và việc cải tiến thêm sẽ yêu cầu phản hồi từ việc triển khai và người dùng.

Các WeakRef đề nghị bao gồm hai mảnh mới lớn các chức năng:

  • Tạo tham chiếu yếu đến các đối tượng với lớp WeakRef
  • Chạy các trình hoàn thiện do người dùng xác định sau khi các đối tượng được thu gom rác, với lớp FinalizationGroup

Trường hợp sử dụng

Cách sử dụng chính cho các tham chiếu yếu là triển khai bộ nhớ đệm hoặc ánh xạ chứa các đối tượng lớn, trong đó người ta muốn một đối tượng lớn không được duy trì chỉ vì nó xuất hiện trong bộ nhớ cache hoặc ánh xạ.

Finalization là việc thực thi mã để dọn dẹp sau khi một đối tượng không thể truy cập được để thực thi chương trình. Trình hoàn thiện do người dùng xác định cho phép một số trường hợp sử dụng mới và có thể giúp ngăn rò rỉ bộ nhớ khi quản lý tài nguyên mà trình thu gom rác không biết.

Nguồn và đọc thêm

https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references


1
Firefox Nightly đã thêm hỗ trợ thử nghiệm cho WeakRef. Đây là một ví dụ triển khai sử dụng nó để tạo phiên bản có thể lặp lại của WeakSet: gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley

3

Các tham chiếu yếu thực sự, không, chưa (nhưng các nhà sản xuất trình duyệt đang xem xét chủ đề này). Nhưng đây là một ý tưởng về cách mô phỏng các tham chiếu yếu.

Bạn có thể xây dựng một bộ nhớ cache để chuyển các đối tượng của mình đi qua. Khi một đối tượng được lưu trữ, bộ nhớ đệm sẽ giữ một dự đoán về lượng bộ nhớ mà đối tượng đó sẽ chiếm. Đối với một số mục, chẳng hạn như lưu trữ hình ảnh, điều này sẽ được giải quyết ngay. Đối với những người khác, điều này sẽ khó khăn hơn.

Khi bạn cần một đối tượng, bạn sẽ yêu cầu bộ nhớ cache cho nó. Nếu bộ nhớ cache có đối tượng, nó sẽ được trả về. Nếu nó không có ở đó, thì mục sẽ được tạo, lưu trữ và sau đó trả về.

Các tham chiếu yếu được mô phỏng bằng các mục xóa bộ nhớ cache, khi tổng dung lượng bộ nhớ dự đoán đạt đến một mức nhất định. Nó sẽ dự đoán những món đồ nào ít được sử dụng nhất dựa trên tần suất chúng được lấy ra, tính theo thời gian chúng được lấy ra trước đây. Một chi phí 'tính toán' cũng có thể được thêm vào, nếu mã tạo ra mục được chuyển vào bộ đệm ẩn dưới dạng một lần đóng. Điều này sẽ cho phép bộ nhớ cache lưu giữ các mục rất tốn kém để tạo hoặc tạo.

Thuật toán xóa là chìa khóa quan trọng, bởi vì nếu bạn làm sai điều này thì cuối cùng bạn có thể xóa các mục phổ biến nhất. Điều này sẽ gây ra hiệu suất khủng khiếp.

Miễn là bộ nhớ đệm là đối tượng duy nhất có các tham chiếu vĩnh viễn đến các đối tượng được lưu trữ, thì hệ thống trên sẽ hoạt động khá tốt như một sự thay thế cho các tham chiếu yếu thực sự.


25
Không phải hầu hết những gì bạn nói không liên quan đến yếu kém sao?
Erik Kaplun

22
@ JL235 - việc sử dụng quan trọng cho các tham chiếu yếu không phải cho bộ nhớ đệm mà cho các trình xử lý sự kiện. Tôi có một số đối tượng, trong khi nó tồn tại, sẽ quan sát một số sự kiện khác - nhưng tôi không muốn thực tế là nó nằm trong danh sách thông báo để tạo thành một tham chiếu cho các mục đích của GC.
Malvolio

7
Tham chiếu yếu không liên quan gì đến bộ nhớ đệm. Tham chiếu yếu nghĩa là bạn muốn theo dõi một thứ gì đó, nhưng nếu không còn tham chiếu nào đến đối tượng đang được theo dõi, bạn cho phép xóa nó.
fabspro,

8
Rõ ràng có một trường hợp sử dụng để tạo bộ nhớ cache bằng cách sử dụng các tham chiếu yếu để tự động hết hạn.
Phil Freeman

5
Bộ nhớ đệm theo truyền thống là lý do hàng đầu cho các tham chiếu yếu. Sự kiện DOM xử lý sự kiện chỉ là một số lỗi của IE Explorer.
axkibe


2

Sử dụng cơ chế bộ nhớ đệm để mô phỏng một tham chiếu yếu, như JL235 đã đề xuất ở trên , là hợp lý. Nếu các tham chiếu yếu vẫn tồn tại nguyên bản, bạn sẽ quan sát thấy một hành vi như sau:

this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not

Trong khi với bộ nhớ cache, bạn sẽ thấy:

this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts

Là người nắm giữ tham chiếu, bạn không nên đưa ra bất kỳ giả định nào về thời điểm nó tham chiếu đến một giá trị, điều này không khác gì sử dụng bộ nhớ cache



-4

EcmaScript 6 (ES Harmony) có một đối tượng WeakMap . Hỗ trợ trình duyệt giữa các trình duyệt hiện đại là khá tốt (3 phiên bản mới nhất của Firefox, chrome và thậm chí cả phiên bản IE sắp tới cũng hỗ trợ nó).


29
Điều này không hoàn toàn giống nhau. A WeakMapkhông cung cấp các tham chiếu yếu đến các đối tượng - nó không phải là các giá trị là tham chiếu yếu trong WeakMap mà là các khóa . Thực tế là các tham chiếu yếu tồn tại trong bản đồ chỉ là một cơ chế ngăn chặn rò rỉ bộ nhớ và người dùng không thể quan sát được.
EyasSH

1
Bạn đúng rằng đó là các phím yếu chứ không phải các giá trị. Nhưng toàn bộ mục đích của việc sử dụng các tham chiếu yếu là cho phép thu gom rác của đối tượng được tham chiếu. OP đã đăng hai liên kết, liên kết thứ hai nói về việc thêm id vào một đối tượng mà bạn không thể mở rộng, và trên thực tế, nó khuyên bạn nên sử dụng WeakHashMap, Java tương đương với WeakMap của JavaScript.
thelastshadow

12
chúc may mắn khi sử dụng WeakMap để triển khai một tham chiếu yếu vì weakmap.get(new String('any possible key that has ever existed or ever will exist'))sẽ luôn như vậy undefined. Không hữu ích. Bỏ phiếu từ chối!
user3338098

-5

http://www.jibbering.com/faq/faq_notes/closures.html

ECMAScript sử dụng tính năng thu gom rác tự động. Đặc tả không xác định chi tiết, để người thực hiện phân loại và một số triển khai được biết là có mức độ ưu tiên rất thấp cho các hoạt động thu gom rác của họ. Nhưng ý tưởng chung là nếu một đối tượng trở nên không thể truy xuất được (do không còn tham chiếu nào đến nó mà nó có thể truy cập được để thực thi mã) thì nó sẽ có sẵn để thu gom rác và một lúc nào đó trong tương lai sẽ bị phá hủy và mọi tài nguyên mà nó đang sử dụng được giải phóng và trả lại. vào hệ thống để sử dụng lại.

Điều này thường xảy ra khi thoát khỏi bối cảnh thực thi. Cấu trúc chuỗi phạm vi, đối tượng Kích hoạt / Biến và bất kỳ đối tượng nào được tạo trong ngữ cảnh thực thi, bao gồm các đối tượng chức năng, sẽ không thể truy cập được nữa và do đó sẽ có sẵn để thu gom rác.

Có nghĩa là không có cái yếu chỉ có cái không còn nữa.


10
Việc tránh các chu trình tham chiếu không phải là lý do duy nhất để sử dụng các tham chiếu yếu. Chúng rất tiện dụng cho việc gộp / bộ nhớ đệm cá thể đối tượng, v.v.
mịn

Định nghĩa của WeakReference không phải là một câu hỏi. Cũng như đồng ý với bình luận ở trên.
Yuri Yaryshev
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.