@@ -137,43 +137,21 @@ class Tiled3DModelSource extends Evented<SourceEvents> implements ISource {
137137 return this . _loaded ;
138138 }
139139
140- loadTile ( tile : Tile , callback : Callback < undefined > ) {
140+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
141+ async loadTile ( tile : Tile , callback : Callback < undefined > ) : Promise < void > {
141142 const url = this . map . _requestManager . normalizeTileURL ( tile . tileID . canonical . url ( this . tiles , this . scheme ) ) ;
142- const request = this . map . _requestManager . transformRequest ( url , ResourceType . Tile ) ;
143- const params : WorkerSourceTiled3dModelRequest = {
144- request,
145- data : undefined ,
146- uid : tile . uid ,
147- tileID : tile . tileID ,
148- tileZoom : tile . tileZoom ,
149- zoom : tile . tileID . overscaledZ ,
150- tileSize : this . tileSize * tile . tileID . overscaleFactor ( ) ,
151- type : this . type ,
152- source : this . id ,
153- scope : this . scope ,
154- showCollisionBoxes : this . map . showCollisionBoxes ,
155- renderSourceType : tile . renderSourceType ,
156- brightness : this . map . style ? ( this . map . style . getBrightness ( ) || 0.0 ) : 0.0 ,
157- pixelRatio : browser . devicePixelRatio ,
158- promoteId : this . promoteId ,
159- } ;
160-
161- const done = ( err ?: AJAXError | null , data ?: WorkerSourceVectorTileResult | null ) => {
162- if ( tile . aborted ) return callback ( null ) ;
163- if ( err && ! isHttpNotFound ( err ) ) return callback ( err ) ;
164- if ( this . map . _refreshExpiredTiles && data ) tile . setExpiryData ( parseExpiryData ( data . headers ) ) ;
165- tile . loadModelData ( data , this . map . painter ) ;
166- tile . state = 'loaded' ;
167- callback ( null ) ;
168- } ;
169143
170- if ( ! tile . actor || tile . state === 'expired' ) {
144+ // The actor/state branch stays synchronous so a re-entrant loadTile dedupes correctly.
145+ const isFresh = ! tile . actor || tile . state === 'expired' ;
146+ if ( isFresh ) {
171147 tile . actor = this . dispatcher . getActor ( ) ;
172- tile . request = tile . actor . sendCancelable ( 'loadTile' , params , { } , done ) ;
173- } else if ( tile . state === 'loading' ) {
174- // schedule tile reloading after it has been loaded
175- tile . reloadCallback = callback ;
176148 } else {
149+ if ( tile . state === 'loading' ) {
150+ // schedule tile reloading after it has been loaded
151+ tile . reloadCallback = callback ;
152+ return ;
153+ }
154+
177155 // If the tile has already been parsed we may just need to reevaluate
178156 if ( tile . buckets ) {
179157 const buckets = Object . values ( tile . buckets ) as Tiled3dModelBucket [ ] ;
@@ -183,8 +161,54 @@ class Tiled3DModelSource extends Evented<SourceEvents> implements ISource {
183161 tile . state = 'loaded' ;
184162 return ;
185163 }
164+ }
165+
166+ const messageType = isFresh ? 'loadTile' : 'reloadTile' ;
167+ const controller = new AbortController ( ) ;
168+ tile . request = controller ;
169+
170+ const done = ( err ?: AJAXError | null , data ?: WorkerSourceVectorTileResult | null ) => {
171+ delete tile . request ;
172+ if ( tile . aborted ) return callback ( null ) ;
173+ if ( err && ! isHttpNotFound ( err ) ) return callback ( err ) ;
174+ if ( this . map . _refreshExpiredTiles && data ) tile . setExpiryData ( parseExpiryData ( data . headers ) ) ;
175+ tile . loadModelData ( data , this . map . painter ) ;
176+ tile . state = 'loaded' ;
177+ callback ( null ) ;
178+
179+ if ( tile . reloadCallback ) {
180+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
181+ this . loadTile ( tile , tile . reloadCallback ) ;
182+ tile . reloadCallback = null ;
183+ }
184+ } ;
186185
187- tile . request = tile . actor . sendCancelable ( 'reloadTile' , params , { } , done ) ;
186+ try {
187+ const request = await this . map . _requestManager . transformRequest ( url , ResourceType . Tile , controller . signal ) ;
188+ if ( controller . signal . aborted ) return callback ( null ) ;
189+
190+ const params : WorkerSourceTiled3dModelRequest = {
191+ request,
192+ data : undefined ,
193+ uid : tile . uid ,
194+ tileID : tile . tileID ,
195+ tileZoom : tile . tileZoom ,
196+ zoom : tile . tileID . overscaledZ ,
197+ tileSize : this . tileSize * tile . tileID . overscaleFactor ( ) ,
198+ type : this . type ,
199+ source : this . id ,
200+ scope : this . scope ,
201+ showCollisionBoxes : this . map . showCollisionBoxes ,
202+ renderSourceType : tile . renderSourceType ,
203+ brightness : this . map . style ? ( this . map . style . getBrightness ( ) || 0.0 ) : 0.0 ,
204+ pixelRatio : browser . devicePixelRatio ,
205+ promoteId : this . promoteId ,
206+ } ;
207+
208+ tile . request = tile . actor . sendCancelable ( messageType , params , { } , done ) ;
209+ } catch ( err ) {
210+ if ( controller . signal . aborted ) return callback ( null ) ;
211+ callback ( err as Error ) ;
188212 }
189213 }
190214
0 commit comments