Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asap scheduler throws error with limiting interval via take #2594

Closed
kwonoj opened this issue May 7, 2017 · 7 comments · Fixed by #2638
Closed

asap scheduler throws error with limiting interval via take #2594

kwonoj opened this issue May 7, 2017 · 7 comments · Fixed by #2638
Assignees
Labels
bug Confirmed bug

Comments

@kwonoj
Copy link
Member

kwonoj commented May 7, 2017

RxJS version:
5.3.1

Code to reproduce:

Rx.Observable.interval(100, Rx.Scheduler.asap).take(3).subscribe((x) => {
  console.log(x);
});

Expected behavior:

Actual behavior:

Additional information:

Error: executing a cancelled action
    at AsapAction.AsyncAction.execute (C:\github\test\node_modules\rxjs\scheduler\AsyncAction.js:83:20)
    at AsapScheduler.flush (C:\github\test\node_modules\rxjs\scheduler\AsapScheduler.js:22:32)
    at ontimeout (timers.js:386:14)
    at tryOnTimeout (timers.js:250:5)
    at Timer.listOnTimeout (timers.js:214:5)
@kwonoj
Copy link
Member Author

kwonoj commented May 7, 2017

Seems this was happening in 5.3.0 as well, not a regression between patches.

@kwonoj kwonoj added the bug Confirmed bug label May 7, 2017
@kwonoj kwonoj changed the title asap scheduler throws error with interval asap scheduler throws error with limiting interval via take May 7, 2017
@trxcllnt
Copy link
Member

trxcllnt commented May 7, 2017

@kwonoj I'll take a look

@dreamershl
Copy link

dreamershl commented Jun 3, 2017

I encounter this issue too. And find it is caused by the AnimationFrameAction unmatched requestAsyncId/recycleAsyncId process.

in request, if the delay is positive value, it will call the super method, the AsynAction will just use the "setInterval". But in the recycleAsyncID triggered by the "unsubscribe", the checking "delay === null && this.delay > 0" will be false. So the corresponding "clearInterval" isn't properly called.

All are just because the "AsyncAction._unsubscribe" function set 'delay' null first before the "recycleAsyncId"

protected _unsubscribe() {

    const id = this.id;
    const scheduler = this.scheduler;
    const actions = scheduler.actions;
    const index = actions.indexOf(this);

    this.work  = null;
    this.delay = null;
    this.state = null;
    this.pending = false;
    this.scheduler = null;

    if (index !== -1) {
      actions.splice(index, 1);
    }

    if (id != null) {
      this.id = this.recycleAsyncId(scheduler, id, null);
    }
  }
       AnimationFrameAction.prototype.requestAsyncId = function (scheduler, id, delay) {
        if (delay === void 0) { delay = 0; }
        // If delay is greater than 0, request as an async action.
        if (delay !== null && delay > 0) {
            return _super.prototype.requestAsyncId.call(this, scheduler, id, delay);
        }
        // Push the action to the end of the scheduler queue.
        scheduler.actions.push(this);
        // If an animation frame has already been requested, don't request another
        // one. If an animation frame hasn't been requested yet, request one. Return
        // the current animation frame request id.
        return scheduler.scheduled || (scheduler.scheduled = AnimationFrame.requestAnimationFrame(scheduler.flush.bind(scheduler, null)));
    };
    AnimationFrameAction.prototype.recycleAsyncId = function (scheduler, id, delay) {
        if (delay === void 0) { delay = 0; }
        // If delay exists and is greater than 0, or if the delay is null (the
        // action wasn't rescheduled) but was originally scheduled as an async
        // action, then recycle as an async action.
        if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) {
            return _super.prototype.recycleAsyncId.call(this, scheduler, id, delay);
        }
        // If the scheduler queue is empty, cancel the requested animation frame and
        // set the scheduled flag to undefined so the next AnimationFrameAction will
        // request its own.
        if (scheduler.actions.length === 0) {
            AnimationFrame.cancelAnimationFrame(id);
            scheduler.scheduled = undefined;
        }
        // Return undefined so the action knows to request a new async id if it's rescheduled.
        return undefined;
    };

@trxcllnt
Copy link
Member

trxcllnt commented Jun 3, 2017

@dreamershl oh thanks, great catch! will have the fix PR'd soon

@trxcllnt
Copy link
Member

trxcllnt commented Jun 3, 2017

@dreamershl @kwonoj PR in #2638

@venikx
Copy link

venikx commented Jun 11, 2017

@trxcllnt Thanks!
I noticed this issue too but didn't know if it was my lack of Scheduler knowledge or not. I'll upgrade ASAP when it gets merged!

@lock
Copy link

lock bot commented Jun 6, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 6, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Confirmed bug
Projects
None yet
4 participants