mirror of
https://github.com/Microsoft/vscode
synced 2024-09-19 18:48:00 +00:00
support AsyncIterator#return
inside AsyncIterableObject and AsyncIterableSource (#209971)
This commit is contained in:
parent
6a28cd9073
commit
9c98056dd7
|
@ -1818,12 +1818,14 @@ export class AsyncIterableObject<T> implements AsyncIterable<T> {
|
|||
private _state: AsyncIterableSourceState;
|
||||
private _results: T[];
|
||||
private _error: Error | null;
|
||||
private readonly _onReturn?: () => void | Promise<void>;
|
||||
private readonly _onStateChanged: Emitter<void>;
|
||||
|
||||
constructor(executor: AsyncIterableExecutor<T>) {
|
||||
constructor(executor: AsyncIterableExecutor<T>, onReturn?: () => void | Promise<void>) {
|
||||
this._state = AsyncIterableSourceState.Initial;
|
||||
this._results = [];
|
||||
this._error = null;
|
||||
this._onReturn = onReturn;
|
||||
this._onStateChanged = new Emitter<void>();
|
||||
|
||||
queueMicrotask(async () => {
|
||||
|
@ -1861,6 +1863,10 @@ export class AsyncIterableObject<T> implements AsyncIterable<T> {
|
|||
}
|
||||
await Event.toPromise(this._onStateChanged.event);
|
||||
} while (true);
|
||||
},
|
||||
return: async () => {
|
||||
this._onReturn?.();
|
||||
return { done: true, value: undefined };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -2020,7 +2026,13 @@ export class AsyncIterableSource<T> {
|
|||
private _errorFn: (error: Error) => void;
|
||||
private _emitFn: (item: T) => void;
|
||||
|
||||
constructor() {
|
||||
/**
|
||||
*
|
||||
* @param onReturn A function that will be called when consuming the async iterable
|
||||
* has finished by the consumer, e.g the for-await-loop has be existed (break, return) early.
|
||||
* This is NOT called when resolving this source by its owner.
|
||||
*/
|
||||
constructor(onReturn?: () => Promise<void> | void) {
|
||||
this._asyncIterable = new AsyncIterableObject(emitter => {
|
||||
|
||||
if (earlyError) {
|
||||
|
@ -2033,7 +2045,7 @@ export class AsyncIterableSource<T> {
|
|||
this._errorFn = (error: Error) => emitter.reject(error);
|
||||
this._emitFn = (item: T) => emitter.emitOne(item);
|
||||
return this._deferred.p;
|
||||
});
|
||||
}, onReturn);
|
||||
|
||||
let earlyError: Error | undefined;
|
||||
let earlyItems: T[] | undefined;
|
||||
|
|
|
@ -1558,4 +1558,123 @@ suite('Async', () => {
|
|||
assert.strictEqual(counter, 4);
|
||||
});
|
||||
});
|
||||
|
||||
suite('AsyncIterableObject', function () {
|
||||
|
||||
|
||||
test('onReturn NOT called', async function () {
|
||||
|
||||
let calledOnReturn = false;
|
||||
const iter = new async.AsyncIterableObject<number>(writer => {
|
||||
writer.emitMany([1, 2, 3, 4, 5]);
|
||||
}, () => {
|
||||
calledOnReturn = true;
|
||||
});
|
||||
|
||||
for await (const item of iter) {
|
||||
assert.strictEqual(typeof item, 'number');
|
||||
}
|
||||
|
||||
assert.strictEqual(calledOnReturn, false);
|
||||
|
||||
});
|
||||
|
||||
test('onReturn called on break', async function () {
|
||||
|
||||
let calledOnReturn = false;
|
||||
const iter = new async.AsyncIterableObject<number>(writer => {
|
||||
writer.emitMany([1, 2, 3, 4, 5]);
|
||||
}, () => {
|
||||
calledOnReturn = true;
|
||||
});
|
||||
|
||||
for await (const item of iter) {
|
||||
assert.strictEqual(item, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
assert.strictEqual(calledOnReturn, true);
|
||||
|
||||
});
|
||||
|
||||
test('onReturn called on return', async function () {
|
||||
|
||||
let calledOnReturn = false;
|
||||
const iter = new async.AsyncIterableObject<number>(writer => {
|
||||
writer.emitMany([1, 2, 3, 4, 5]);
|
||||
}, () => {
|
||||
calledOnReturn = true;
|
||||
});
|
||||
|
||||
await (async function test() {
|
||||
for await (const item of iter) {
|
||||
assert.strictEqual(item, 1);
|
||||
return;
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
assert.strictEqual(calledOnReturn, true);
|
||||
|
||||
});
|
||||
|
||||
|
||||
test('onReturn called on throwing', async function () {
|
||||
|
||||
let calledOnReturn = false;
|
||||
const iter = new async.AsyncIterableObject<number>(writer => {
|
||||
writer.emitMany([1, 2, 3, 4, 5]);
|
||||
}, () => {
|
||||
calledOnReturn = true;
|
||||
});
|
||||
|
||||
try {
|
||||
for await (const item of iter) {
|
||||
assert.strictEqual(item, 1);
|
||||
throw new Error();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
assert.strictEqual(calledOnReturn, true);
|
||||
});
|
||||
});
|
||||
|
||||
suite('AsyncIterableSource', function () {
|
||||
|
||||
test('onReturn is wired up', async function () {
|
||||
let calledOnReturn = false;
|
||||
const source = new async.AsyncIterableSource<number>(() => { calledOnReturn = true; });
|
||||
|
||||
source.emitOne(1);
|
||||
source.emitOne(2);
|
||||
source.emitOne(3);
|
||||
source.resolve();
|
||||
|
||||
for await (const item of source.asyncIterable) {
|
||||
assert.strictEqual(item, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
assert.strictEqual(calledOnReturn, true);
|
||||
|
||||
});
|
||||
|
||||
test('onReturn is wired up 2', async function () {
|
||||
let calledOnReturn = false;
|
||||
const source = new async.AsyncIterableSource<number>(() => { calledOnReturn = true; });
|
||||
|
||||
source.emitOne(1);
|
||||
source.emitOne(2);
|
||||
source.emitOne(3);
|
||||
source.resolve();
|
||||
|
||||
for await (const item of source.asyncIterable) {
|
||||
assert.strictEqual(typeof item, 'number');
|
||||
}
|
||||
|
||||
assert.strictEqual(calledOnReturn, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue