test_finalizationRegistry.html (5230B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Test FinalizationRegistry works in the browser</title> 6 <script src="/tests/SimpleTest/SimpleTest.js"></script> 7 <script type="application/javascript"> 8 let registry1, holdings1; 9 let registry2, holdings2; 10 let registry3, holdings3; 11 let registry4, holdings4; 12 let registry5, holdings5; 13 let registry6, holdings6; 14 let registry7, holdings7; 15 let registry8, holdings8; 16 let registry9, holdings9; 17 18 let object4 = {}; 19 20 function go() { 21 SimpleTest.waitForExplicitFinish(); 22 23 // Registry with no registered objects. 24 holdings1 = []; 25 registry1 = new FinalizationRegistry(v => { holdings1.push(v); }); 26 27 // Registry with three registered objects. 28 holdings2 = []; 29 registry2 = new FinalizationRegistry(v => { holdings2.push(v); }); 30 registry2.register({}, 1); 31 registry2.register({}, 2); 32 registry2.register({}, 3); 33 34 // Registry with registered object that is then unregistered. 35 holdings3 = []; 36 registry3 = new FinalizationRegistry(v => { holdings3.push(v); }); 37 let token3 = {} 38 registry3.register({}, 1, token3); 39 registry3.unregister(token3); 40 41 // Registry with registered object that doesn't die. 42 holdings4 = []; 43 registry4 = new FinalizationRegistry(v => { holdings4.push(v); }); 44 registry4.register(object4, 1); 45 46 // Registry observing cyclic JS data structure. 47 holdings5 = []; 48 registry5 = new FinalizationRegistry(v => { holdings5.push(v); }); 49 registry5.register(makeJSCycle(4), 5); 50 51 // Registry observing DOM object without preserved wrappers. 52 holdings6 = []; 53 registry6 = new FinalizationRegistry(v => { holdings6.push(v); }); 54 registry6.register(document.createElement("div"), 6); 55 56 // Registry observing DOM object with preserved wrappers. 57 holdings7 = []; 58 registry7 = new FinalizationRegistry(v => { holdings7.push(v); }); 59 let object = document.createElement("div"); 60 object.someProperty = true; 61 registry7.register(object, 7); 62 object = null; 63 64 // Registry observing reachable DOM object without preserved wrappers. 65 holdings8 = []; 66 registry8 = new FinalizationRegistry(v => { holdings8.push(v); }); 67 document.body.appendChild(document.createElement("div")); 68 registry8.register(document.body.lastChild, 8); 69 70 // Registry observing cyclic DOM/JS data structure. 71 holdings9 = []; 72 registry9 = new FinalizationRegistry(v => { holdings9.push(v); }); 73 registry9.register(makeDOMCycle(4), 9); 74 75 // Need to run full GC/CC/GC cycle to collect cyclic garbage through DOM 76 // and JS heaps. 77 SpecialPowers.DOMWindowUtils.garbageCollect(); 78 SpecialPowers.DOMWindowUtils.cycleCollect(); 79 SpecialPowers.DOMWindowUtils.garbageCollect(); 80 81 // Microtasks are run before cleanup callbacks. 82 Promise.resolve().then(() => { 83 is(holdings1.length, 0); 84 is(holdings2.length, 0); 85 is(holdings3.length, 0); 86 is(holdings4.length, 0); 87 is(holdings5.length, 0); 88 is(holdings6.length, 0); 89 is(holdings7.length, 0); 90 is(holdings8.length, 0); 91 is(holdings9.length, 0); 92 }); 93 94 // setTimeout queues a task which will run after cleanup callbacks. 95 setTimeout(task2, 0); 96 } 97 98 function task2() { 99 is(holdings1.length, 0); 100 101 let result = holdings2.sort((a, b) => a - b); 102 is(result.length, 3); 103 is(result[0], 1); 104 is(result[1], 2); 105 is(result[2], 3); 106 107 is(holdings3.length, 0); 108 is(holdings4.length, 0); 109 110 is(holdings5.length, 1); 111 is(holdings5[0], 5); 112 113 is(holdings6.length, 1); 114 is(holdings6[0], 6); 115 116 is(holdings7.length, 1); 117 is(holdings7[0], 7); 118 119 is(holdings8.length, 0); 120 121 is(holdings9.length, 1); 122 is(holdings9[0], 9); 123 124 document.body.removeChild(document.body.lastChild); 125 126 SpecialPowers.DOMWindowUtils.garbageCollect(); 127 SpecialPowers.DOMWindowUtils.cycleCollect(); 128 SpecialPowers.DOMWindowUtils.garbageCollect(); 129 130 setTimeout(task3, 0); 131 } 132 133 function task3() { 134 is(holdings8.length, 1); 135 is(holdings8[0], 8); 136 137 SimpleTest.finish(); 138 } 139 140 function makeJSCycle(size) { 141 let first = {}; 142 let current = first; 143 for (let i = 0; i < size; i++) { 144 current.next = {}; 145 current = current.next; 146 } 147 current.next = first; 148 return first; 149 } 150 151 function makeDOMCycle(size) { 152 let first = {}; 153 let current = first; 154 for (let i = 0; i < size; i++) { 155 if (i % 2 === 0) { 156 current.next = document.createElement("div"); 157 } else { 158 current.next = {}; 159 } 160 current = current.next; 161 } 162 current.next = first; 163 return first; 164 } 165 </script> 166 </head> 167 <body onload="go()"></body> 168 </html>