Skip to content

Commit

Permalink
v4: Remove next-tick dependency
Browse files Browse the repository at this point in the history
For years, we had a unique external dependency (the only non-dev
dependency) called "next-tick" allowing us to schedule callbacks in
micro-tasks, either to provide asynchronous browser API shims or for
some specific logic where we would prefer to bring some asynchronicity
in without the need of bringing the event loop into this.

We were not too happy having this dependency because the name "nextTick"
didn't ring a bell to most RxPlayer developers who never really worked
with node.JS before, whereas the "microtask" concept is generally more
known and understood in JavaScript environments, or at least is easier
to look for on the internet.

Moreover, now that we consider that a Promise object has to be
accessible globally in the current environment as a precondition to run
the RxPlayer (so IE11 is now only supported as long as `Promise` is
polyfilled by the application, which almost everyone still
supporting that target in a complex media application does anyway) and
that specification-following Promise implementations include a mean
to schedule microtasks, we have a very easy way to provide a shim in
cases where the `queueMicroTask` global function is not already
supported.

So this commit removes the next-tick dependency and replace it by either
the natively-provided `queueMicroTask` function or a Promise-based
ponyfill if not, naming the result `queueMicroTask`, which should be
much more familiar to JS dev and is a simpler implementation than what
`next-tick` provided, we moreover now control.

Its removal also means that now the RxPlayer has no dependency from
an application perspective, which may eliminates some groups of issues
applications sometimes have when doing weird things with their
webpack/vite configs :p

We may still have an issue for Promise implementations which do not
rely on microtasks (or even event loop events, we shouldn't have an
issue with those), but I would expect that the very large majority of
Promise polyfills in use today respect that key part of the spec.
  • Loading branch information
peaBerberian committed Nov 8, 2023
1 parent 5ede134 commit d77a736
Show file tree
Hide file tree
Showing 9 changed files with 16 additions and 49 deletions.
1 change: 0 additions & 1 deletion demo/full/scripts/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import "../../../src/typings/globals.d";
import "../../../src/typings/next-tick";
import "../../../src/typings/object-assign";
13 changes: 0 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,6 @@
"type": "git",
"url": "git://github.com/canalplus/rx-player.git"
},
"dependencies": {
"next-tick": "1.1.0"
},
"devDependencies": {
"@babel/core": "7.23.0",
"@babel/plugin-transform-runtime": "7.22.15",
Expand Down
4 changes: 2 additions & 2 deletions src/compat/patch_webkit_source_buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

import nextTick from "next-tick";
import EventEmitter from "../utils/event_emitter";
import queueMicrotask from "../utils/queue_microtask";
import globalScope from "./global_scope";
import isNode from "./is_node";

Expand Down Expand Up @@ -57,7 +57,7 @@ export default function patchWebkitSourceBuffer() : void {

sourceBufferWebkitProto._emitUpdate =
function(eventName : string, val : unknown) {
nextTick(() => {
queueMicrotask(() => {
/* eslint-disable no-invalid-this */
this.trigger(eventName, val);
this.updating = false;
Expand Down
4 changes: 2 additions & 2 deletions src/core/stream/adaptation/adaptation_stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import nextTick from "next-tick";
import config from "../../../config";
import { formatError } from "../../../errors";
import log from "../../../log";
Expand All @@ -7,6 +6,7 @@ import assertUnreachable from "../../../utils/assert_unreachable";
import cancellableSleep from "../../../utils/cancellable_sleep";
import noop from "../../../utils/noop";
import objectAssign from "../../../utils/object_assign";
import queueMicrotask from "../../../utils/queue_microtask";
import SharedReference, {
createMappedReference,
IReadOnlySharedReference,
Expand Down Expand Up @@ -192,7 +192,7 @@ export default function AdaptationStream(
// conditions where the inner logic would be called synchronously before
// the next observation (which may reflect very different playback conditions)
// is actually received.
return nextTick(() => {
return queueMicrotask(() => {
playbackObserver.listen(() => {
if (fnCancelSignal.isCancelled()) {
return;
Expand Down
6 changes: 3 additions & 3 deletions src/core/stream/orchestrator/stream_orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
* limitations under the License.
*/

import nextTick from "next-tick";
import config from "../../../config";
import { MediaError } from "../../../errors";
import log from "../../../log";
import Manifest, {
IDecipherabilityUpdateElement,
Period,
} from "../../../manifest";
import queueMicrotask from "../../../utils/queue_microtask";
import {
createMappedReference,
IReadOnlySharedReference,
Expand Down Expand Up @@ -351,7 +351,7 @@ export default function StreamOrchestrator(
// Schedule micro task before checking the last playback observation
// to reduce the risk of race conditions where the next observation
// was going to be emitted synchronously.
nextTick(() => {
queueMicrotask(() => {
if (orchestratorCancelSignal.isCancelled()) {
return ;
}
Expand Down Expand Up @@ -554,7 +554,7 @@ export default function StreamOrchestrator(
// conditions where the inner logic would be called synchronously before
// the next observation (which may reflect very different playback
// conditions) is actually received.
return nextTick(() => {
return queueMicrotask(() => {
if (innerCancelSignal.isCancelled()) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/stream/period/period_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import nextTick from "next-tick";
import config from "../../../config";
import {
formatError,
Expand All @@ -26,6 +25,7 @@ import {
Period,
} from "../../../manifest";
import objectAssign from "../../../utils/object_assign";
import queueMicrotask from "../../../utils/queue_microtask";
import { getLeftSizeOfBufferedTimeRange } from "../../../utils/ranges";
import SharedReference, {
IReadOnlySharedReference,
Expand Down Expand Up @@ -362,7 +362,7 @@ export default function PeriodStream(
// is actually received.
// It can happen when `askForMediaSourceReload` is called as a side-effect of
// the same event that triggers the playback observation to be emitted.
nextTick(() => {
queueMicrotask(() => {
playbackObserver.listen(() => {
if (cancelSignal.isCancelled()) {
return;
Expand Down
23 changes: 0 additions & 23 deletions src/typings/next-tick.d.ts

This file was deleted.

7 changes: 7 additions & 0 deletions src/utils/queue_microtask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default typeof queueMicrotask === "function" ?
queueMicrotask :
function queueMicrotaskPonyfill(
cb: () => void
): void {
Promise.resolve().then(cb, () => cb());
};

0 comments on commit d77a736

Please sign in to comment.