Skip to content

Commit aebf165

Browse files
JiaLiPassiondylhunn
authored andcommitted
fix(zone.js): should ignore multiple resolve call (#45283)
Close #44913 The following case is not handled correctly by `zone.js`. ``` const delayedPromise = new Promise((resolve) => { setTimeout(resolve, 1, 'timeout'); }); new Promise((resolve) => { resolve(delayedPromise); resolve('second call'); }).then(console.log); ``` It should output `timeout`, since the promise is resolved by the 1st resolve, the `second call` should be ignored. So this is a bug that the original implementation not ensure the `resolve` is only called once. PR Close #45283
1 parent d36fa11 commit aebf165

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

packages/zone.js/lib/common/promise.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
9696
const REJECTED_NO_CATCH = 0;
9797

9898
function makeResolver(promise: ZoneAwarePromise<any>, state: boolean): (value: any) => void {
99-
return (v) => {
99+
return (v: any) => {
100100
try {
101101
resolvePromise(promise, state, v);
102102
} catch (err) {
@@ -445,7 +445,11 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
445445
(promise as any)[symbolState] = UNRESOLVED;
446446
(promise as any)[symbolValue] = []; // queue;
447447
try {
448-
executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED));
448+
const onceWrapper = once();
449+
executor &&
450+
executor(
451+
onceWrapper(makeResolver(promise, RESOLVED)),
452+
onceWrapper(makeResolver(promise, REJECTED)));
449453
} catch (error) {
450454
resolvePromise(promise, false, error);
451455
}

packages/zone.js/test/common/Promise.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,5 +836,73 @@ describe(
836836
expect(Subclass.thenArgs.length).toBe(1);
837837
});
838838
});
839+
840+
describe('resolve/reject multiple times', () => {
841+
it('should ignore second resolve', (done) => {
842+
const nested = new Promise(res => setTimeout(() => res('nested')));
843+
const p = new Promise(res => {
844+
res(nested);
845+
res(1);
846+
});
847+
p.then(v => {
848+
expect(v).toBe('nested');
849+
done();
850+
});
851+
});
852+
it('should ignore second resolve', (done) => {
853+
const nested = new Promise(res => setTimeout(() => res('nested')));
854+
const p = new Promise(res => {
855+
res(1);
856+
res(nested);
857+
});
858+
p.then(v => {
859+
expect(v).toBe(1);
860+
done();
861+
});
862+
});
863+
it('should ignore second reject', (done) => {
864+
const p = new Promise((res, rej) => {
865+
rej(1);
866+
rej(2);
867+
});
868+
p.then(
869+
v => {
870+
fail('should not get here');
871+
},
872+
err => {
873+
expect(err).toBe(1);
874+
done();
875+
});
876+
});
877+
it('should ignore resolve after reject', (done) => {
878+
const p = new Promise((res, rej) => {
879+
rej(1);
880+
res(2);
881+
});
882+
p.then(
883+
v => {
884+
fail('should not get here');
885+
},
886+
err => {
887+
expect(err).toBe(1);
888+
done();
889+
});
890+
});
891+
it('should ignore reject after resolve', (done) => {
892+
const nested = new Promise(res => setTimeout(() => res('nested')));
893+
const p = new Promise((res, rej) => {
894+
res(nested);
895+
rej(1);
896+
});
897+
p.then(
898+
v => {
899+
expect(v).toBe('nested');
900+
done();
901+
},
902+
err => {
903+
fail('should not be here');
904+
});
905+
});
906+
});
839907
});
840908
}));

0 commit comments

Comments
 (0)