MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1import { test, summary } from './helpers.js';
2
3console.log('Async Loop Closure Tests\n');
4
5let results = {};
6
7function delay(ms) {
8 return new Promise(resolve => setTimeout(resolve, ms));
9}
10
11async function testForLetClosure() {
12 const fns = [];
13 for (let i = 0; i < 3; i++) {
14 await delay(5);
15 fns.push(() => i);
16 }
17 return fns.map(f => f()).join(',');
18}
19const p1 = testForLetClosure().then(v => {
20 results.forLetClosure = v;
21});
22
23async function testBlockScopedCapture() {
24 const fns = [];
25 for (let i = 0; i < 3; i++) {
26 const captured = i * 10;
27 await delay(5);
28 fns.push(() => captured);
29 }
30 return fns.map(f => f()).join(',');
31}
32const p2 = testBlockScopedCapture().then(v => {
33 results.blockScopedCapture = v;
34});
35
36async function testNestedLoops() {
37 const fns = [];
38 for (let i = 0; i < 2; i++) {
39 for (let j = 0; j < 2; j++) {
40 const captured = `${i}-${j}`;
41 await delay(5);
42 fns.push(() => captured);
43 }
44 }
45 return fns.map(f => f()).join(',');
46}
47const p3 = testNestedLoops().then(v => {
48 results.nestedLoops = v;
49});
50
51async function testWhileLoop() {
52 let i = 0;
53 const values = [];
54 while (i < 3) {
55 const captured = i;
56 await delay(5);
57 values.push(captured);
58 i++;
59 }
60 return values.join(',');
61}
62const p4 = testWhileLoop().then(v => {
63 results.whileLoop = v;
64});
65
66async function testMultipleAwaits() {
67 const fns = [];
68 for (let i = 0; i < 3; i++) {
69 const captured = i;
70 await delay(5);
71 await delay(5);
72 fns.push(() => captured);
73 }
74 return fns.map(f => f()).join(',');
75}
76const p5 = testMultipleAwaits().then(v => {
77 results.multipleAwaits = v;
78});
79
80async function loopTask(id) {
81 const taskResults = [];
82 for (let i = 0; i < 3; i++) {
83 const captured = `${id}:${i}`;
84 await delay(5);
85 taskResults.push(() => captured);
86 }
87 return taskResults.map(fn => fn());
88}
89
90async function testSequentialTasks() {
91 const a = await loopTask('A');
92 const b = await loopTask('B');
93 return { a: a.join(','), b: b.join(',') };
94}
95const p6 = testSequentialTasks().then(v => {
96 results.sequentialTasks = v;
97});
98
99async function testAsyncArrowInLoop() {
100 const fns = [];
101 for (let i = 0; i < 3; i++) {
102 const captured = i;
103 fns.push(async () => {
104 await delay(5);
105 return captured;
106 });
107 }
108 const values = await Promise.all(fns.map(f => f()));
109 return values.join(',');
110}
111const p7 = testAsyncArrowInLoop().then(v => {
112 results.asyncArrowInLoop = v;
113});
114
115async function testTryCatchInLoop() {
116 const values = [];
117 for (let i = 0; i < 3; i++) {
118 const captured = i;
119 try {
120 await delay(5);
121 values.push(captured);
122 } catch (e) {
123 values.push('error');
124 }
125 }
126 return values.join(',');
127}
128const p8 = testTryCatchInLoop().then(v => {
129 results.tryCatchInLoop = v;
130});
131
132async function testDoWhile() {
133 let i = 0;
134 const values = [];
135 do {
136 const captured = i;
137 await delay(5);
138 values.push(captured);
139 i++;
140 } while (i < 3);
141 return values.join(',');
142}
143const p9 = testDoWhile().then(v => {
144 results.doWhile = v;
145});
146
147async function testConditionalAwait() {
148 const fns = [];
149 for (let i = 0; i < 3; i++) {
150 const captured = i;
151 if (i % 2 === 0) {
152 await delay(5);
153 }
154 fns.push(() => captured);
155 }
156 return fns.map(f => f()).join(',');
157}
158const p10 = testConditionalAwait().then(v => {
159 results.conditionalAwait = v;
160});
161
162async function inner(id, val) {
163 const arr = [];
164 for (let i = 0; i < 2; i++) {
165 await delay(1);
166 arr.push(`${id}:${val}:${i}`);
167 }
168 return arr;
169}
170
171async function outer(id) {
172 const taskResults = [];
173 for (let j = 0; j < 2; j++) {
174 await delay(1);
175 const r = await inner(id, j);
176 taskResults.push(...r);
177 }
178 return taskResults;
179}
180
181const p11 = Promise.all([outer('A'), outer('B'), outer('C')]).then(([a, b, c]) => {
182 results.nestedAsyncA = a.join(',');
183 results.nestedAsyncB = b.join(',');
184 results.nestedAsyncC = c.join(',');
185});
186
187Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11]).then(() => {
188 test('for-let with async closure', results.forLetClosure, '0,1,2');
189 test('block-scoped capture', results.blockScopedCapture, '0,10,20');
190 test('nested loops', results.nestedLoops, '0-0,0-1,1-0,1-1');
191 test('while loop const', results.whileLoop, '0,1,2');
192 test('multiple awaits per iteration', results.multipleAwaits, '0,1,2');
193 test('sequential tasks A', results.sequentialTasks.a, 'A:0,A:1,A:2');
194 test('sequential tasks B', results.sequentialTasks.b, 'B:0,B:1,B:2');
195 test('async arrow in loop', results.asyncArrowInLoop, '0,1,2');
196 test('try-catch in loop', results.tryCatchInLoop, '0,1,2');
197 test('do-while with const', results.doWhile, '0,1,2');
198 test('conditional await', results.conditionalAwait, '0,1,2');
199 test('nested async calls A', results.nestedAsyncA, 'A:0:0,A:0:1,A:1:0,A:1:1');
200 test('nested async calls B', results.nestedAsyncB, 'B:0:0,B:0:1,B:1:0,B:1:1');
201 test('nested async calls C', results.nestedAsyncC, 'C:0:0,C:0:1,C:1:0,C:1:1');
202 summary();
203});