Skip to content

Commit 14042fb

Browse files
robwalkercofacebook-github-bot
authored andcommitted
Don't crash when promise task is cancelled before its resolved (#29969)
Summary: This pull request fixes a potential `TypeError` in TaskQueue.js, that happens if a promise is added to the task queue, which is cancelled between the promise starting and resolving. The exact error this resolves is ```js TypeError: TaskQueue: Error resolving Promise in task gen1: Cannot set property ‘popable’ of undefined 167 | queueStackSize: this._queueStack.length, 168 | }); > 169 | this._queueStack[stackIdx].popable = true; | ^ 170 | this.hasTasksToProcess() && this._onMoreTasks(); 171 | }) 172 | .catch(ex => { at Libraries/Interaction/TaskQueue.js:169:46 ``` This specific error was also reported in #16321 ## Changelog [General] [Fixed] - Prevent TypeError in TaskQueue when cancelling a started but not resolved promise. Pull Request resolved: #29969 Test Plan: The added test demonstrates the error, if run without the fixed applied to TaskQueue.js. This is a race condition error, so is difficult to replicate! Reviewed By: yungsters Differential Revision: D23785972 Pulled By: appden fbshipit-source-id: ddb8d06b37d296ee934ff39815cf5c9026d73871
1 parent 1438543 commit 14042fb

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

Libraries/Interaction/TaskQueue.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class TaskQueue {
156156
// happens once it is fully processed.
157157
this._queueStack.push({tasks: [], popable: false});
158158
const stackIdx = this._queueStack.length - 1;
159+
const stackItem = this._queueStack[stackIdx];
159160
DEBUG && infoLog('TaskQueue: push new queue: ', {stackIdx});
160161
DEBUG && infoLog('TaskQueue: exec gen task ' + task.name);
161162
task
@@ -166,7 +167,7 @@ class TaskQueue {
166167
stackIdx,
167168
queueStackSize: this._queueStack.length,
168169
});
169-
this._queueStack[stackIdx].popable = true;
170+
stackItem.popable = true;
170171
this.hasTasksToProcess() && this._onMoreTasks();
171172
})
172173
.catch(ex => {

Libraries/Interaction/__tests__/TaskQueue-test.js

+16
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,20 @@ describe('TaskQueue', () => {
150150
expect(task1).not.toBeCalled();
151151
expect(taskQueue.hasTasksToProcess()).toBe(false);
152152
});
153+
154+
it('should not crash when task is cancelled between being started and resolved', () => {
155+
const task1 = jest.fn(() => {
156+
return new Promise(resolve => {
157+
setTimeout(() => {
158+
resolve();
159+
}, 1);
160+
});
161+
});
162+
163+
taskQueue.enqueue({gen: task1, name: 'gen1'});
164+
taskQueue.processNext();
165+
taskQueue.cancelTasks([task1]);
166+
167+
jest.runAllTimers();
168+
});
153169
});

0 commit comments

Comments
 (0)