@@ -13,6 +13,9 @@ export class PreviewService {
1313 userStore : UserStore
1414 authStore : AuthStore
1515
16+ /** Ongoing preview requests, so concurrent loads of the same key share one fetch. */
17+ private inFlightPreviews = new Map < string , Promise < string > > ( )
18+
1619 constructor ( {
1720 clientService,
1821 userStore,
@@ -81,9 +84,15 @@ export class PreviewService {
8184 if ( hit && hit . etag === resource . etag ) {
8285 return hit . src
8386 }
87+
8488 try {
85- const { src, size } = await this . fetchPreviewBlob ( options , signal )
86- return cacheService . filePreview . set ( key , { src, size, etag : resource . etag } , 0 ) . src
89+ let request = this . inFlightPreviews . get ( key )
90+ if ( ! request ) {
91+ request = this . fetchAndCachePreview ( options , key , signal )
92+ this . inFlightPreviews . set ( key , request )
93+ }
94+
95+ return await request
8796 } catch ( e ) {
8897 if ( silenceErrors ) {
8998 return
@@ -92,6 +101,19 @@ export class PreviewService {
92101 }
93102 }
94103
104+ private async fetchAndCachePreview (
105+ options : LoadPreviewOptions ,
106+ key : string ,
107+ signal ?: AbortSignal
108+ ) : Promise < string > {
109+ try {
110+ const { src, size } = await this . fetchPreviewBlob ( options , signal )
111+ return cacheService . filePreview . set ( key , { src, size, etag : options . resource . etag } , 0 ) . src
112+ } finally {
113+ this . inFlightPreviews . delete ( key )
114+ }
115+ }
116+
95117 private buildQueryString ( options : BuildQueryStringOptions ) : string {
96118 return stringify ( {
97119 scalingup : options . scalingup || 0 ,
0 commit comments