timcassell / ProtoPromise

Robust and efficient library for management of asynchronous operations in C#/.Net.
MIT License
147 stars 13 forks source link

`PromiseYielder.WaitOneFrame()` waits an extra frame. #199

Closed timcassell closed 1 year ago

timcassell commented 1 year ago

This test fails. It appears to be due to the optimization I added that continues to use the already-running coroutine rather than starting a new coroutine. I'm not sure why it happens, but the first call waits 1 frame, and successive (recursive) calls wait 2 frames.

[UnityTest]
public IEnumerator PromiseYielderWaitOneFrame_WaitsOneFrameMultiple(
    [Values] RunnerType runnerType)
{
    int currentFrame = Time.frameCount;

    var promise = PromiseYielder.WaitOneFrame(GetRunner(runnerType))
        .Then(() =>
        {
            Assert.AreEqual(currentFrame + 1, Time.frameCount);
            return PromiseYielder.WaitOneFrame(GetRunner(runnerType));
        })
        .Then(() =>
        {
            Assert.AreEqual(currentFrame + 2, Time.frameCount);
            return PromiseYielder.WaitOneFrame(GetRunner(runnerType));
        })
        .Then(() =>
        {
            Assert.AreEqual(currentFrame + 3, Time.frameCount);
            return PromiseYielder.WaitOneFrame(GetRunner(runnerType));
        })
        .Then(() =>
        {
            Assert.AreEqual(currentFrame + 4, Time.frameCount);
        });
    using (var yieldInstruction = promise.ToYieldInstruction())
    {
        yield return yieldInstruction;
        if (yieldInstruction.State == Promise.State.Rejected)
            yieldInstruction.GetResult();
    }
}

Unfortunately, it seems the only way to fix it is to remove the optimization and always start a new coroutine. At least I am working on more optimized Unity awaits (#196) to offset the performance regression.