Skip to content

Commit 45d5677

Browse files
authored
Improve download progress firing algorithm
Closes #41.
1 parent 41216b3 commit 45d5677

File tree

1 file changed

+120
-110
lines changed

1 file changed

+120
-110
lines changed

Diff for: index.bs

+120-110
Original file line numberDiff line numberDiff line change
@@ -861,127 +861,137 @@ enum AIRewriterLength { "as-is", "shorter", "longer" };
861861

862862
1. Wait for the total number of bytes to be downloaded to become determined, and let that number be |totalBytes|.
863863

864+
This number must be equal to the number of bytes that the user agent needs to download at the present time, not including any that have already been downloaded.
865+
866+
<div class="note">
867+
<p>For example, if another tab has started the download and it is 90% finished, and the user agent is planning to share the model across all tabs, then |totalBytes| will be 10% of the size of the model, not 100% of the size of the model.
868+
869+
<p>This prevents the web developer-perceived progress from suddenly jumping from 0% to 90%, and then taking a long time to go from 90% to 100%. It also provides some protection against the (admittedly not very powerful) fingerprinting vector of measuring the current download progress across multiple sites.
870+
</div>
871+
872+
1. Let |lastProgressFraction| be 0.
873+
864874
1. Let |lastProgressTime| be the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
865875

866876
1. Perform |fireProgressEvent| given 0.
867877

868878
1. While true:
869879

870-
1. If one or more bytes have been downloaded, then:
871-
872-
1. If the [=monotonic clock=]'s [=monotonic clock/unsafe current time=] minus |lastProgressTime| is greater than 50 ms, then:
873-
874-
1. Let |bytesSoFar| be the number of bytes downloaded so far.
875-
876-
1. [=Assert=]: |bytesSoFar| is greater than 0 and less than or equal to |totalBytes|.
877-
878-
1. Let |rawProgressFraction| be |bytesSoFar| divided by |totalBytes|.
879-
880-
1. Let |progressFraction| be [$floor$](|rawProgressFraction| &times; 65,536) &divide; 65,536.
881-
882-
1. Perform |fireProgressEvent| given |progressFraction|.
883-
884-
<div class="note">
885-
<p>We use a fraction, instead of firing a progress event with the number of bytes downloaded, to avoid giving precise information about the size of the model or other material being downloaded.</p>
886-
887-
<p>|progressFraction| is calculated from |rawProgressFraction| to give a precision of one part in 2<sup>16</sup>. This ensures that over most internet speeds and with most model sizes, the {{ProgressEvent/loaded}} value will be different from the previous one that was fired ~50 milliseconds ago.</p>
888-
889-
<details>
890-
<summary>Full calculation</summary>
891-
892-
<p>Assume a 5 GiB download size, and a 20 Mbps download speed (chosen as a number on the lower range from [this source](https://worldpopulationreview.com/country-rankings/internet-speeds-by-country)). Then, downloading 5 GiB will take:</p>
893-
894-
<math style="display:block math">
895-
<mtable>
896-
<mtr>
897-
<mtd></mtd>
898-
<mtd style="text-align: left">
899-
<mn>5</mn>
900-
<mtext>&nbsp;GiB</mtext>
901-
902-
<mo>×</mo>
903-
<mfrac>
904-
<mrow>
905-
<msup>
906-
<mn>2</mn>
907-
<mn>30</mn>
908-
</msup>
909-
<mtext>&nbsp;bytes</mtext>
910-
</mrow>
911-
<mtext>GiB</mtext>
912-
</mfrac>
913-
914-
<mo>×</mo>
915-
<mfrac>
916-
<mrow>
917-
<mn>8</mn>
918-
<mtext>&nbsp;bits</mtext>
919-
</mrow>
920-
<mtext>bytes</mtext>
921-
</mfrac>
922-
923-
<mo>÷</mo>
924-
<mfrac>
925-
<mrow>
926-
<mn>20</mn>
927-
<mo>×</mo>
928-
<msup>
929-
<mn>10</mn>
930-
<mn>6</mn>
931-
</msup>
932-
<mtext>&nbsp;bits</mtext>
933-
</mrow>
934-
<mtext>s</mtext>
935-
</mfrac>
936-
937-
<mo>×</mo>
938-
<mfrac>
939-
<mrow>
940-
<mn>1000</mn>
941-
<mtext>&nbsp;ms</mtext>
942-
</mrow>
943-
<mtext>s</mtext>
944-
</mfrac>
945-
946-
<mo>÷</mo>
947-
<mfrac>
948-
<mrow>
949-
<mn>50</mn>
950-
<mtext>&nbsp;ms</mtext>
951-
</mrow>
952-
<mtext>interval</mtext>
953-
</mfrac>
954-
</mtd>
955-
</mtr>
956-
957-
<mtr>
958-
<mtd>
959-
<mo>=</mo>
960-
</mtd>
961-
<mtd style="text-align: left">
962-
<mn>49,950</mn>
963-
<mtext>&nbsp;intervals</mtext>
964-
</mtd>
965-
</mtr>
966-
</mtable>
967-
</math>
968-
969-
Rounding up to the nearest power of two gives a conservative estimate of 65,536 fifty millisecond intervals, so we want to give progress to 1 part in 2<sup>16</sup>.
970-
</details>
971-
</div>
972-
973-
1. If |bytesSoFar| equals |totalBytes|, then [=iteration/break=].
974-
975-
<p class="note">Since this is the only exit condition for the loop, we are guaranteed to fire a {{AICreateMonitor/downloadprogress}} event for the 100% mark.</p>
976-
977-
1. Set |lastProgressTime| to the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
978-
979-
1. Otherwise, if downloading has failed and cannot continue, then:
880+
1. If downloading has failed, then:
980881

981882
1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to [=reject=] |promise| with a "{{NetworkError}}" {{DOMException}}.
982883

983884
1. Abort these steps.
984885

886+
1. Let |bytesSoFar| be the number of bytes downloaded so far.
887+
888+
1. [=Assert=]: |bytesSoFar| is greater than or equal to 0, and less than or equal to |totalBytes|.
889+
890+
1. If the [=monotonic clock=]'s [=monotonic clock/unsafe current time=] minus |lastProgressTime| is greater than 50 ms, or |bytesSoFar| equals |totalBytes|, then:
891+
892+
1. Let |rawProgressFraction| be |bytesSoFar| divided by |totalBytes|.
893+
894+
1. Let |progressFraction| be [$floor$](|rawProgressFraction| &times; 65,536) &divide; 65,536.
895+
896+
<div class="note">
897+
<p>We use a fraction, instead of firing a progress event with the number of bytes downloaded, to avoid giving precise information about the size of the model or other material being downloaded.</p>
898+
899+
<p>|progressFraction| is calculated from |rawProgressFraction| to give a precision of one part in 2<sup>16</sup>. This ensures that over most internet speeds and with most model sizes, the {{ProgressEvent/loaded}} value will be different from the previous one that was fired ~50 milliseconds ago.</p>
900+
901+
<details>
902+
<summary>Full calculation</summary>
903+
904+
<p>Assume a 5 GiB download size, and a 20 Mbps download speed (chosen as a number on the lower range from [this source](https://worldpopulationreview.com/country-rankings/internet-speeds-by-country)). Then, downloading 5 GiB will take:</p>
905+
906+
<math style="display:block math">
907+
<mtable>
908+
<mtr>
909+
<mtd></mtd>
910+
<mtd style="text-align: left">
911+
<mn>5</mn>
912+
<mtext>&nbsp;GiB</mtext>
913+
914+
<mo>×</mo>
915+
<mfrac>
916+
<mrow>
917+
<msup>
918+
<mn>2</mn>
919+
<mn>30</mn>
920+
</msup>
921+
<mtext>&nbsp;bytes</mtext>
922+
</mrow>
923+
<mtext>GiB</mtext>
924+
</mfrac>
925+
926+
<mo>×</mo>
927+
<mfrac>
928+
<mrow>
929+
<mn>8</mn>
930+
<mtext>&nbsp;bits</mtext>
931+
</mrow>
932+
<mtext>bytes</mtext>
933+
</mfrac>
934+
935+
<mo>÷</mo>
936+
<mfrac>
937+
<mrow>
938+
<mn>20</mn>
939+
<mo>×</mo>
940+
<msup>
941+
<mn>10</mn>
942+
<mn>6</mn>
943+
</msup>
944+
<mtext>&nbsp;bits</mtext>
945+
</mrow>
946+
<mtext>s</mtext>
947+
</mfrac>
948+
949+
<mo>×</mo>
950+
<mfrac>
951+
<mrow>
952+
<mn>1000</mn>
953+
<mtext>&nbsp;ms</mtext>
954+
</mrow>
955+
<mtext>s</mtext>
956+
</mfrac>
957+
958+
<mo>÷</mo>
959+
<mfrac>
960+
<mrow>
961+
<mn>50</mn>
962+
<mtext>&nbsp;ms</mtext>
963+
</mrow>
964+
<mtext>interval</mtext>
965+
</mfrac>
966+
</mtd>
967+
</mtr>
968+
969+
<mtr>
970+
<mtd>
971+
<mo>=</mo>
972+
</mtd>
973+
<mtd style="text-align: left">
974+
<mn>49,950</mn>
975+
<mtext>&nbsp;intervals</mtext>
976+
</mtd>
977+
</mtr>
978+
</mtable>
979+
</math>
980+
981+
Rounding up to the nearest power of two gives a conservative estimate of 65,536 fifty millisecond intervals, so we want to give progress to 1 part in 2<sup>16</sup>.
982+
</details>
983+
</div>
984+
985+
1. If |progressFraction| is not equal to |lastProgressFraction|, then perform |fireProgressEvent| given |progressFraction|.
986+
987+
1. If |bytesSoFar| equals |totalBytes|, then [=iteration/break=].
988+
989+
<p class="note">Since this is the only non-failure exit condition for the loop, we will never miss firing a {{AICreateMonitor/downloadprogress}} event for the 100% mark.</p>
990+
991+
1. Set |lastProgressFraction| to |progressFraction|.
992+
993+
1. Set |lastProgressTime| to the [=monotonic clock=]'s [=monotonic clock/unsafe current time=].
994+
985995
1. [=If aborted=], then:
986996

987997
1. [=Queue a global task=] on the [=AI task source=] given |realm|'s [=realm/global object=] to perform the following steps:

0 commit comments

Comments
 (0)