Adopt runWhenIdle
(#133173)
This commit is contained in:
parent
7be48d527a
commit
2fa5d4f76e
|
@ -968,6 +968,45 @@ export interface IdleDeadline {
|
|||
readonly didTimeout: boolean;
|
||||
timeRemaining(): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#:~:text=than%204%2C%20then-,set%20timeout%20to%204,-.
|
||||
*
|
||||
* Works similarly to `setTimeout(0)` but doesn't suffer from the 4ms artificial delay
|
||||
* that browsers set when the nesting level is > 5.
|
||||
*/
|
||||
const scheduleAsyncWork = (() => {
|
||||
if (typeof globalThis.postMessage === 'function' && !globalThis.importScripts) {
|
||||
interface IQueueElement {
|
||||
id: number;
|
||||
callback: () => void;
|
||||
}
|
||||
let pending: IQueueElement[] = [];
|
||||
globalThis.addEventListener('message', (e: MessageEvent) => {
|
||||
if (e.data && e.data.vscodeScheduleAsyncWork) {
|
||||
for (let i = 0, len = pending.length; i < len; i++) {
|
||||
const candidate = pending[i];
|
||||
if (candidate.id === e.data.vscodeScheduleAsyncWork) {
|
||||
pending.splice(i, 1);
|
||||
candidate.callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let lastId = 0;
|
||||
return (callback: () => void) => {
|
||||
const myId = ++lastId;
|
||||
pending.push({
|
||||
id: myId,
|
||||
callback: callback
|
||||
});
|
||||
globalThis.postMessage({ vscodeScheduleAsyncWork: myId }, '*');
|
||||
};
|
||||
}
|
||||
return (callback: () => void) => setTimeout(callback);
|
||||
})();
|
||||
|
||||
/**
|
||||
* Execute the callback the next time the browser is idle
|
||||
*/
|
||||
|
@ -979,8 +1018,11 @@ declare function cancelIdleCallback(handle: number): void;
|
|||
(function () {
|
||||
if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {
|
||||
runWhenIdle = (runner) => {
|
||||
const handle = setTimeout(() => {
|
||||
const end = Date.now() + 15; // one frame at 64fps
|
||||
scheduleAsyncWork(() => {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
const end = Date.now() + 3; // yield often
|
||||
runner(Object.freeze({
|
||||
didTimeout: true,
|
||||
timeRemaining() {
|
||||
|
@ -995,7 +1037,6 @@ declare function cancelIdleCallback(handle: number): void;
|
|||
return;
|
||||
}
|
||||
disposed = true;
|
||||
clearTimeout(handle);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ import { TextModel } from 'vs/editor/common/model/textModel';
|
|||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { MultilineTokensBuilder, countEOL } from 'vs/editor/common/model/tokensStore';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
|
||||
const enum Constants {
|
||||
CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048
|
||||
|
@ -255,19 +255,26 @@ export class TextModelTokenization extends Disposable {
|
|||
this._beginBackgroundTokenization();
|
||||
}
|
||||
|
||||
private _isScheduled = false;
|
||||
private _beginBackgroundTokenization(): void {
|
||||
if (this._textModel.isAttachedToEditor() && this._hasLinesToTokenize()) {
|
||||
platform.setImmediate(() => {
|
||||
if (this._isDisposed) {
|
||||
// disposed in the meantime
|
||||
return;
|
||||
}
|
||||
this._revalidateTokensNow();
|
||||
});
|
||||
if (this._isScheduled || !this._textModel.isAttachedToEditor() || !this._hasLinesToTokenize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isScheduled = true;
|
||||
runWhenIdle((deadline) => {
|
||||
this._isScheduled = false;
|
||||
|
||||
if (this._isDisposed) {
|
||||
// disposed in the meantime
|
||||
return;
|
||||
}
|
||||
|
||||
this._revalidateTokensNow(deadline);
|
||||
});
|
||||
}
|
||||
|
||||
private _revalidateTokensNow(): void {
|
||||
private _revalidateTokensNow(deadline: IdleDeadline): void {
|
||||
const textModelLastLineNumber = this._textModel.getLineCount();
|
||||
|
||||
const MAX_ALLOWED_TIME = 1;
|
||||
|
@ -275,7 +282,7 @@ export class TextModelTokenization extends Disposable {
|
|||
const sw = StopWatch.create(false);
|
||||
let tokenizedLineNumber = -1;
|
||||
|
||||
while (this._hasLinesToTokenize()) {
|
||||
do {
|
||||
if (sw.elapsed() > MAX_ALLOWED_TIME) {
|
||||
// Stop if MAX_ALLOWED_TIME is reached
|
||||
break;
|
||||
|
@ -286,7 +293,7 @@ export class TextModelTokenization extends Disposable {
|
|||
if (tokenizedLineNumber >= textModelLastLineNumber) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (this._hasLinesToTokenize() && deadline.timeRemaining() > 0);
|
||||
|
||||
this._beginBackgroundTokenization();
|
||||
this._textModel.setTokens(builder.tokens, !this._hasLinesToTokenize());
|
||||
|
|
Loading…
Reference in a new issue