@@ -34,97 +34,108 @@ let currentEntangledPendingCount: number = 0;
3434let currentEntangledLane : Lane = NoLane ;
3535
3636export function requestAsyncActionContext < S > (
37- actionReturnValue : mixed ,
38- finishedState : S ,
39- ) : Thenable < S > | S {
40- if (
41- actionReturnValue !== null &&
42- typeof actionReturnValue === 'object' &&
43- typeof actionReturnValue . then === 'function'
44- ) {
45- // This is an async action.
46- //
47- // Return a thenable that resolves once the action scope (i.e. the async
48- // function passed to startTransition) has finished running.
37+ actionReturnValue : Thenable < mixed > ,
38+ // If this is provided, this resulting thenable resolves to this value instead
39+ // of the return value of the action. This is a perf trick to avoid composing
40+ // an extra async function.
41+ overrideReturnValue : S | null ,
42+ ) : Thenable < S > {
43+ // This is an async action.
44+ //
45+ // Return a thenable that resolves once the action scope (i.e. the async
46+ // function passed to startTransition) has finished running.
4947
50- const thenable : Thenable < mixed > = ( actionReturnValue : any ) ;
51- let entangledListeners ;
52- if ( currentEntangledListeners === null ) {
53- // There's no outer async action scope. Create a new one.
54- entangledListeners = currentEntangledListeners = [ ] ;
55- currentEntangledPendingCount = 0 ;
56- currentEntangledLane = requestTransitionLane ( ) ;
57- } else {
58- entangledListeners = currentEntangledListeners ;
59- }
48+ const thenable : Thenable < S > = ( actionReturnValue : any ) ;
49+ let entangledListeners ;
50+ if ( currentEntangledListeners === null ) {
51+ // There's no outer async action scope. Create a new one.
52+ entangledListeners = currentEntangledListeners = [ ] ;
53+ currentEntangledPendingCount = 0 ;
54+ currentEntangledLane = requestTransitionLane ( ) ;
55+ } else {
56+ entangledListeners = currentEntangledListeners ;
57+ }
6058
61- currentEntangledPendingCount ++ ;
62- let resultStatus = 'pending' ;
63- let rejectedReason ;
64- thenable . then (
65- ( ) => {
66- resultStatus = 'fulfilled' ;
67- pingEngtangledActionScope ( ) ;
68- } ,
69- error => {
70- resultStatus = 'rejected' ;
71- rejectedReason = error ;
72- pingEngtangledActionScope ( ) ;
73- } ,
74- ) ;
59+ currentEntangledPendingCount ++ ;
7560
76- // Create a thenable that represents the result of this action, but doesn't
77- // resolve until the entire entangled scope has finished.
78- //
79- // Expressed using promises:
80- // const [thisResult] = await Promise.all([thisAction, entangledAction]);
81- // return thisResult;
82- const resultThenable = createResultThenable < S > ( entangledListeners ) ;
61+ // Create a thenable that represents the result of this action, but doesn't
62+ // resolve until the entire entangled scope has finished.
63+ //
64+ // Expressed using promises:
65+ // const [thisResult] = await Promise.all([thisAction, entangledAction]);
66+ // return thisResult;
67+ const resultThenable = createResultThenable < S > ( entangledListeners ) ;
8368
84- // Attach a listener to fill in the result.
85- entangledListeners . push ( ( ) => {
86- switch ( resultStatus ) {
87- case 'fulfilled' : {
88- const fulfilledThenable : FulfilledThenable < S > = ( resultThenable : any ) ;
89- fulfilledThenable . status = 'fulfilled' ;
90- fulfilledThenable . value = finishedState ;
91- break ;
92- }
93- case 'rejected' : {
94- const rejectedThenable : RejectedThenable < S > = (resultThenable: any);
95- rejectedThenable.status = 'rejected';
96- rejectedThenable.reason = rejectedReason;
97- break;
98- }
99- case 'pending ':
100- default : {
101- // The listener above should have been called first, so `resultStatus`
102- // should already be set to the correct value.
103- throw new Error (
104- 'Thenable should have already resolved. This ' +
105- 'is a bug in React.' ,
106- ) ;
107- }
108- }
109- } ) ;
69+ let resultStatus = 'pending' ;
70+ let resultValue ;
71+ let rejectedReason ;
72+ thenable . then (
73+ ( value : S ) => {
74+ resultStatus = 'fulfilled' ;
75+ resultValue = overrideReturnValue !== null ? overrideReturnValue : value ;
76+ pingEngtangledActionScope ( ) ;
77+ } ,
78+ error => {
79+ resultStatus = 'rejected' ;
80+ rejectedReason = error ;
81+ pingEngtangledActionScope ( ) ;
82+ } ,
83+ ) ;
11084
111- return resultThenable ;
112- } else {
113- // This is not an async action, but it may be part of an outer async action.
114- if ( currentEntangledListeners === null ) {
115- return finishedState ;
116- } else {
117- // Return a thenable that does not resolve until the entangled actions
118- // have finished.
119- const entangledListeners = currentEntangledListeners ;
120- const resultThenable = createResultThenable < S > ( entangledListeners ) ;
121- entangledListeners . push ( ( ) => {
85+ // Attach a listener to fill in the result.
86+ entangledListeners . push ( ( ) => {
87+ switch ( resultStatus ) {
88+ case 'fulfilled' : {
12289 const fulfilledThenable : FulfilledThenable < S > = ( resultThenable : any ) ;
12390 fulfilledThenable . status = 'fulfilled' ;
124- fulfilledThenable.value = finishedState;
125- } ) ;
126- return resultThenable ;
91+ fulfilledThenable . value = resultValue ;
92+ break ;
93+ }
94+ case 'rejected' : {
95+ const rejectedThenable : RejectedThenable < S > = (resultThenable: any);
96+ rejectedThenable.status = 'rejected';
97+ rejectedThenable.reason = rejectedReason;
98+ break;
99+ }
100+ case 'pending ':
101+ default : {
102+ // The listener above should have been called first, so `resultStatus`
103+ // should already be set to the correct value.
104+ throw new Error (
105+ 'Thenable should have already resolved. This ' + 'is a bug in React.' ,
106+ ) ;
107+ }
127108 }
109+ } ) ;
110+
111+ return resultThenable ;
112+ }
113+
114+ export function requestSyncActionContext < S > (
115+ actionReturnValue: mixed,
116+ // If this is provided, this resulting thenable resolves to this value instead
117+ // of the return value of the action. This is a perf trick to avoid composing
118+ // an extra async function.
119+ overrideReturnValue: S | null,
120+ ): Thenable< S > | S {
121+ const resultValue : S =
122+ overrideReturnValue !== null
123+ ? overrideReturnValue
124+ : ( actionReturnValue : any ) ;
125+ // This is not an async action, but it may be part of an outer async action.
126+ if ( currentEntangledListeners === null ) {
127+ return resultValue ;
128+ } else {
129+ // Return a thenable that does not resolve until the entangled actions
130+ // have finished.
131+ const entangledListeners = currentEntangledListeners ;
132+ const resultThenable = createResultThenable < S > ( entangledListeners ) ;
133+ entangledListeners . push ( ( ) => {
134+ const fulfilledThenable : FulfilledThenable < S > = (resultThenable: any);
135+ fulfilledThenable.status = 'fulfilled';
136+ fulfilledThenable.value = resultValue;
137+ } ) ;
138+ return resultThenable ;
128139 }
129140}
130141
0 commit comments