@@ -85,6 +85,8 @@ export class Http2Channel extends EventEmitter implements Channel {
8585 private readonly target : url . URL ;
8686 private readonly defaultAuthority : string ;
8787 private connectivityState : ConnectivityState = ConnectivityState . IDLE ;
88+ // Helper Promise object only used in the implementation of connect().
89+ private connecting : Promise < void > | null = null ;
8890 /* For now, we have up to one subchannel, which will exist as long as we are
8991 * connecting or trying to connect */
9092 private subChannel : http2 . ClientHttp2Session | null = null ;
@@ -127,6 +129,7 @@ export class Http2Channel extends EventEmitter implements Channel {
127129 this . subChannel . removeListener ( 'connect' , this . subChannelConnectCallback ) ;
128130 this . subChannel . removeListener ( 'close' , this . subChannelCloseCallback ) ;
129131 this . subChannel = null ;
132+ this . emit ( 'shutdown' ) ;
130133 clearTimeout ( this . backoffTimerId ) ;
131134 }
132135 break ;
@@ -279,15 +282,38 @@ export class Http2Channel extends EventEmitter implements Channel {
279282 return stream ;
280283 }
281284
285+ /**
286+ * Attempts to connect, returning a Promise that resolves when the connection
287+ * is successful, or rejects if the channel is shut down.
288+ */
282289 connect ( ) : Promise < void > {
283- return new Promise ( ( resolve ) => {
284- this . transitionToState ( [ ConnectivityState . IDLE ] , ConnectivityState . CONNECTING ) ;
285- if ( this . connectivityState === ConnectivityState . READY ) {
286- setImmediate ( resolve ) ;
287- } else {
288- this . once ( 'connect' , resolve ) ;
290+ if ( this . connectivityState === ConnectivityState . READY ) {
291+ return Promise . resolve ( ) ;
292+ } else if ( this . connectivityState === ConnectivityState . SHUTDOWN ) {
293+ return Promise . reject ( new Error ( 'Channel has been shut down' ) ) ;
294+ } else {
295+ // In effect, this.connecting is only assigned upon the first attempt to
296+ // transition from IDLE to CONNECTING, so this condition could have also
297+ // been (connectivityState === IDLE).
298+ if ( ! this . connecting ) {
299+ this . connecting = new Promise ( ( resolve , reject ) => {
300+ this . transitionToState ( [ ConnectivityState . IDLE ] , ConnectivityState . CONNECTING ) ;
301+ const onConnect = ( ) => {
302+ this . connecting = null ;
303+ this . removeListener ( 'shutdown' , onShutdown ) ;
304+ resolve ( ) ;
305+ } ;
306+ const onShutdown = ( ) => {
307+ this . connecting = null ;
308+ this . removeListener ( 'connect' , onConnect ) ;
309+ reject ( new Error ( 'Channel has been shut down' ) ) ;
310+ } ;
311+ this . once ( 'connect' , onConnect ) ;
312+ this . once ( 'shutdown' , onShutdown ) ;
313+ } ) ;
289314 }
290- } ) ;
315+ return this . connecting ;
316+ }
291317 }
292318
293319 getConnectivityState ( ) : ConnectivityState {
0 commit comments