react-native-fast-image 9.3.0 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -257,7 +257,7 @@ It can also be set in `style`; the prop wins. Either one overrides `resizeMode`.
257
257
 
258
258
  **Type:** `ResizeMode` · **Default:** `'cover'`
259
259
 
260
- **Deprecated:** Use `objectFit` instead, except for `'repeat'`, which has no `objectFit` value and isn't deprecated.
260
+ **Deprecated:** Use `objectFit` instead.
261
261
 
262
262
  How the image fills the view.
263
263
 
@@ -22,10 +22,13 @@ import java.util.ArrayList;
22
22
  import java.util.Arrays;
23
23
  import java.util.Comparator;
24
24
  import java.util.HashMap;
25
+ import java.util.HashSet;
26
+ import java.util.Iterator;
25
27
  import java.util.List;
26
28
  import java.util.Map;
27
- import java.util.PriorityQueue;
29
+ import java.util.Set;
28
30
  import java.util.TreeMap;
31
+ import java.util.TreeSet;
29
32
  import java.util.concurrent.ConcurrentHashMap;
30
33
  import java.util.concurrent.LinkedBlockingQueue;
31
34
  import java.util.concurrent.ThreadFactory;
@@ -64,13 +67,18 @@ import okio.BufferedSource;
64
67
  // once every request has read what it needed.
65
68
  //
66
69
  // At most MAX_RUNNING downloads run at once, as SDWebImage's downloader limits
67
- // them; the others wait to send their request, most urgent first (Glide's
68
- // priority: views before preloads). A running download's response is read as
69
- // soon as it arrives (not on OkHttp's dispatcher, which React Native's
70
- // networking shares): a response left unread on an HTTP/2 connection would
71
- // hold back the others on it. A download that stalls fails like any other,
72
- // with the timeouts of the clients (FastImageOkHttpProgressGlideModule), which
73
- // only count once it has started.
70
+ // them, and at most as many wait for their response from a host as the
71
+ // client's dispatcher sends to a host at once (5 by default): OkHttp would
72
+ // hold the others in the order they came, where a more urgent request can't
73
+ // move them up. The others wait to send their request, most urgent first
74
+ // (Glide's priority: views before preloads), and the most urgent one waiting
75
+ // for a host's room keeps a running slot, so less urgent downloads to other
76
+ // hosts can't take them all. A running download's response is read as soon
77
+ // as it arrives, on its own thread (OkHttp counts a request to its host until
78
+ // its callback returns): a response left unread on an HTTP/2 connection
79
+ // would hold back the others on it. A download that stalls fails like any
80
+ // other, with the timeouts of the clients (FastImageOkHttpProgressGlideModule),
81
+ // which only count once it has started.
74
82
  final class FastImageSharedDownloads {
75
83
  // The longest response kept in memory, and the most bytes held in memory
76
84
  // for downloads at once: encoded images (not decoded bitmaps, which
@@ -98,9 +106,9 @@ final class FastImageSharedDownloads {
98
106
  // lock).
99
107
  private static final Map<String, Download> downloads = new HashMap<>();
100
108
  // Guarded by downloads: downloads waiting to start, most urgent first, then
101
- // in the order they were asked for; how many are running; and the bytes
102
- // held in memory.
103
- private static final PriorityQueue<Download> queue = new PriorityQueue<>(11, new Comparator<Download>() {
109
+ // in the order they were asked for; how many are running, and how many
110
+ // wait for their response from each host; and the bytes held in memory.
111
+ private static final TreeSet<Download> queue = new TreeSet<>(new Comparator<Download>() {
104
112
  @Override
105
113
  public int compare(Download a, Download b) {
106
114
  int byPriority = a.priority.compareTo(b.priority);
@@ -109,6 +117,7 @@ final class FastImageSharedDownloads {
109
117
  });
110
118
  private static long orders = 0;
111
119
  private static int running = 0;
120
+ private static final Map<String, Integer> sentTo = new HashMap<>();
112
121
  private static long held = 0;
113
122
  // Stores not yet released (see busy()).
114
123
  private static final AtomicInteger open = new AtomicInteger();
@@ -165,9 +174,10 @@ final class FastImageSharedDownloads {
165
174
  static String busy() {
166
175
  synchronized (downloads) {
167
176
  int stores = open.get();
168
- if (downloads.isEmpty() && queue.isEmpty() && running == 0 && held == 0 && stores == 0) return null;
177
+ if (downloads.isEmpty() && queue.isEmpty() && running == 0 && sentTo.isEmpty() && held == 0
178
+ && stores == 0) return null;
169
179
  return downloads.size() + " downloads, " + queue.size() + " waiting, " + running + " running, "
170
- + held + " bytes in memory, " + stores + " stores open";
180
+ + sentTo + " waiting for a response, " + held + " bytes in memory, " + stores + " stores open";
171
181
  }
172
182
  }
173
183
 
@@ -253,13 +263,25 @@ final class FastImageSharedDownloads {
253
263
  }
254
264
  }
255
265
 
256
- // Starts the downloads waiting that can run now.
266
+ // Starts the downloads waiting that can run now, most urgent first: those
267
+ // whose host has room, leaving a slot for each host without (see above).
257
268
  private static void startQueued() {
258
269
  List<Download> starting = new ArrayList<>();
259
270
  List<Request> requests = new ArrayList<>();
260
271
  synchronized (downloads) {
261
- while (running < MAX_RUNNING && !queue.isEmpty()) {
262
- Download download = queue.poll();
272
+ Set<String> full = new HashSet<>();
273
+ Iterator<Download> waiting = queue.iterator();
274
+ while (running + full.size() < MAX_RUNNING && waiting.hasNext()) {
275
+ Download download = waiting.next();
276
+ String host = download.request.url().host();
277
+ Integer sent = sentTo.get(host);
278
+ if (sent != null && sent >= download.client.dispatcher().getMaxRequestsPerHost()) {
279
+ full.add(host);
280
+ continue;
281
+ }
282
+ waiting.remove();
283
+ sentTo.put(host, sent == null ? 1 : sent + 1);
284
+ download.host = host;
263
285
  download.queued = false;
264
286
  download.running = true;
265
287
  running++;
@@ -539,6 +561,10 @@ final class FastImageSharedDownloads {
539
561
  private final long order;
540
562
  private boolean queued = false;
541
563
  private boolean running = false;
564
+ // Guarded by downloads. The host its request was sent to, until its
565
+ // response (or failure) arrives.
566
+ @Nullable
567
+ private String host;
542
568
  // Guarded by this. The call, once started, and whether the download
543
569
  // was cancelled (before it started, it doesn't).
544
570
  @Nullable
@@ -585,7 +611,9 @@ final class FastImageSharedDownloads {
585
611
  return;
586
612
  }
587
613
  Download download;
588
- boolean queuedOne = false;
614
+ // Queued one, or moved a waiting one to another url (whose host
615
+ // can have room).
616
+ boolean queueChanged = false;
589
617
  InputStream ready = null;
590
618
  synchronized (downloads) {
591
619
  // Cancelled before it got here.
@@ -601,7 +629,7 @@ final class FastImageSharedDownloads {
601
629
  downloads.put(fetcher.key, download);
602
630
  download.queued = true;
603
631
  queue.add(download);
604
- queuedOne = true;
632
+ queueChanged = true;
605
633
  } else if (download.queued) {
606
634
  // A more urgent request moves it up (until it leaves).
607
635
  if (fetcher.priority.compareTo(download.priority) < 0) download.reprioritize(fetcher.priority);
@@ -612,6 +640,7 @@ final class FastImageSharedDownloads {
612
640
  download.url = fetcher.url;
613
641
  download.client = fetcher.client;
614
642
  download.request = request;
643
+ queueChanged = true;
615
644
  }
616
645
  }
617
646
  fetcher.download = download;
@@ -627,7 +656,7 @@ final class FastImageSharedDownloads {
627
656
  }
628
657
  }
629
658
  if (ready != null) fetcher.deliver(ready, callback);
630
- if (queuedOne) startQueued();
659
+ if (queueChanged) startQueued();
631
660
  }
632
661
 
633
662
  // Sends the request (off the main thread, and outside the locks:
@@ -656,10 +685,24 @@ final class FastImageSharedDownloads {
656
685
  if (started != null) started.cancel();
657
686
  }
658
687
 
688
+ // With downloads locked: its request has its response, failed, or
689
+ // wasn't sent, so another can be sent to its host.
690
+ private void responded() {
691
+ if (host == null) return;
692
+ int sent = sentTo.get(host) - 1;
693
+ if (sent == 0) {
694
+ sentTo.remove(host);
695
+ } else {
696
+ sentTo.put(host, sent);
697
+ }
698
+ host = null;
699
+ }
700
+
659
701
  // It no longer runs: the next download waiting can start.
660
702
  private void stopped() {
661
703
  synchronized (downloads) {
662
704
  if (!running) return;
705
+ responded();
663
706
  running = false;
664
707
  FastImageSharedDownloads.running--;
665
708
  }
@@ -853,6 +896,7 @@ final class FastImageSharedDownloads {
853
896
  fromHttpCache = response.networkResponse() == null && response.cacheResponse() != null;
854
897
  final long length = body.contentLength();
855
898
  synchronized (downloads) {
899
+ responded();
856
900
  // No progress without a length.
857
901
  if (length <= 0) silent = true;
858
902
  }
@@ -862,6 +906,7 @@ final class FastImageSharedDownloads {
862
906
  readInto(body, length);
863
907
  }
864
908
  });
909
+ startQueued();
865
910
  }
866
911
 
867
912
  // Sends a progress step, unless the download has stopped: checked and
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
125
125
 
126
126
  tintColor?: number | string,
127
127
  objectFit?: ?ObjectFit,
128
- // Deprecated: objectFit, except for 'repeat'.
128
+ // Deprecated: use objectFit.
129
129
  resizeMode?: ?ResizeModes,
130
130
  fallback?: ?boolean,
131
131
  recyclingKey?: ?string,
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
125
125
 
126
126
  tintColor?: number | string,
127
127
  objectFit?: ?ObjectFit,
128
- // Deprecated: objectFit, except for 'repeat'.
128
+ // Deprecated: use objectFit.
129
129
  resizeMode?: ?ResizeModes,
130
130
  fallback?: ?boolean,
131
131
  recyclingKey?: ?string,
package/dist/index.d.ts CHANGED
@@ -329,8 +329,7 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
329
329
  * image repeats its first frame, and `defaultSource` repeats too.
330
330
  *
331
331
  * @default 'cover'
332
- * @deprecated Use `objectFit` instead, except for `'repeat'`, which has no
333
- * `objectFit` value and isn't deprecated.
332
+ * @deprecated Use `objectFit` instead.
334
333
  */
335
334
  resizeMode?: ResizeMode;
336
335
  /**
@@ -568,8 +567,7 @@ export interface PreloadFailure {
568
567
  export type PreloadResult = PreloadSuccess | PreloadFailure;
569
568
  export interface FastImageStaticProperties {
570
569
  /**
571
- * @deprecated Use the `objectFit` prop instead of `resizeMode`, except for
572
- * `'repeat'`.
570
+ * @deprecated Use the `objectFit` prop instead of `resizeMode`.
573
571
  */
574
572
  resizeMode: typeof resizeMode;
575
573
  priority: typeof priority;
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
125
125
 
126
126
  tintColor?: number | string,
127
127
  objectFit?: ?ObjectFit,
128
- // Deprecated: objectFit, except for 'repeat'.
128
+ // Deprecated: use objectFit.
129
129
  resizeMode?: ?ResizeModes,
130
130
  fallback?: ?boolean,
131
131
  recyclingKey?: ?string,
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
125
125
 
126
126
  tintColor?: number | string,
127
127
  objectFit?: ?ObjectFit,
128
- // Deprecated: objectFit, except for 'repeat'.
128
+ // Deprecated: use objectFit.
129
129
  resizeMode?: ?ResizeModes,
130
130
  fallback?: ?boolean,
131
131
  recyclingKey?: ?string,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "9.3.0",
3
+ "version": "9.3.1",
4
4
  "description": "FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",