Display captions based on video time
This is an ideal case for bisect/binary search.
Provided you did the right thing and the caption array is sorted by time.

Additional optimization for sequential playback is to check the adjacent captions' time before bisect. Sometimes we might want to rewind a couple of seconds back so let's cache the previous caption as well.

// sequential playback uses the adjacent caption to avoid array enumeration
this.captionState = {prevStart:-1, start:-1, end:-1, nextEnd:-1};

this.onUpdateTime = function(currentTime, totalTime) {
    var state = this.captionState;
    if (currentTime &gt;= state.prevStart &amp;&amp; currentTime &lt;= state.start) {
        return showCaption(state.index - 1);
    }
    if (currentTime &gt;= state.end &amp;&amp; currentTime &lt;= state.nextEnd) {
        return showCaption(state.index + 1);
    }
    if (currentTime &gt;= state.start &amp;&amp; currentTime &lt;= state.end) {
        return false;
    }

    // bisect the caption array sorted by time
    var a = 0, b = $scope.chapters.length - 1;
    while (a &lt; b - 1) {
        var c = (a + b) / 2 |0;
        if ($scope.chapters[c].time &gt; currentTime) {
            b = c;
        } else {
            a = c;
        }
    }

    // find a caption that starts before currentTime amidst [b], [b-1], [b-2]
    // or hide the current caption if none found e.g. the first one doesn't start at 0
    for (var i = 0; i &lt;= 2; i++) {
        if (b - i &lt; 0 || currentTime &gt;= $scope.chapters[b - i].time) {
            return showCaption(b - i);
        }
    }

    function showCaption(index) {
        var current = $scope.chapters[index];
        if (!current) {
            $rootScope.caption = '';
            $scope.$apply();
            return false;
        }
        $rootScope.caption = current.caption;
        $scope.$apply();

        var prev = $scope.chapters[index - 1];
        var next = $scope.chapters[index + 1];
        var next2nd = $scope.chapters[index + 2];

        state.index = index;
        state.prevStart = prev ? prev.time : -1;
        state.start = current.time;
        state.end = next ? next.time : totalTime;
        state.nextEnd = next2nd ? next2nd.time : totalTime;
        return true;
    }
};