* Runs a task manually. * * This can be useful for running tasks in response to events as opposed to * automatically running when host element state changes. * * @param args an optional set of arguments to use for this task run. If args * is not given, the args function is call
(args?: T)
| 312 | * this run. |
| 313 | */ |
| 314 | async run(args?: T) { |
| 315 | args ??= this._getArgs(); |
| 316 | |
| 317 | // Remember the args for potential future automatic runs. |
| 318 | // TODO (justinfagnani): add test |
| 319 | this._previousArgs = args; |
| 320 | |
| 321 | if (this._status === TaskStatus.PENDING) { |
| 322 | this._abortController?.abort(); |
| 323 | } else { |
| 324 | // Clear the last complete task run in INITIAL because it may be a resolved |
| 325 | // promise. Also clear if COMPLETE or ERROR because the value returned by |
| 326 | // awaiting taskComplete may have changed since last run. |
| 327 | this._taskComplete = undefined; |
| 328 | this._resolveTaskComplete = undefined; |
| 329 | this._rejectTaskComplete = undefined; |
| 330 | } |
| 331 | |
| 332 | this._status = TaskStatus.PENDING; |
| 333 | let result!: R | typeof initialState; |
| 334 | let error: unknown; |
| 335 | |
| 336 | // Request an update to report pending state. |
| 337 | if (this.autoRun === 'afterUpdate') { |
| 338 | // Avoids a change-in-update warning |
| 339 | queueMicrotask(() => this._host.requestUpdate()); |
| 340 | } else { |
| 341 | this._host.requestUpdate(); |
| 342 | } |
| 343 | |
| 344 | const key = ++this._callId; |
| 345 | this._abortController = new AbortController(); |
| 346 | let errored = false; |
| 347 | try { |
| 348 | result = await this._task(args!, {signal: this._abortController.signal}); |
| 349 | } catch (e) { |
| 350 | errored = true; |
| 351 | error = e; |
| 352 | } |
| 353 | // If this is the most recent task call, process this value. |
| 354 | if (this._callId === key) { |
| 355 | if (result === initialState) { |
| 356 | this._status = TaskStatus.INITIAL; |
| 357 | } else { |
| 358 | if (errored === false) { |
| 359 | try { |
| 360 | this._onComplete?.(result as R); |
| 361 | } catch { |
| 362 | // Ignore user errors from onComplete. |
| 363 | } |
| 364 | this._status = TaskStatus.COMPLETE; |
| 365 | this._resolveTaskComplete?.(result as R); |
| 366 | } else { |
| 367 | try { |
| 368 | this._onError?.(error); |
| 369 | } catch { |
| 370 | // Ignore user errors from onError. |
| 371 | } |
no test coverage detected