请教or反馈一个Promise的bug

问题描述Promise.resolve().then()方法应该是异步的,但是在脚本中却以一个诡异的半同步方式展现。

问题复现:挂载一个脚本,脚本代码(typescript)如下所示:

    onLoad() {
        cc.log("onload")
        this.init()
    }

    start() {
        cc.log("start")
    }

    init() {
        Promise.resolve().then(() => {
            for (let i = 0; i < 1000; i += 1) {
                cc.log("init-promise")
            }
        })
        cc.log("init-no-promise")
    }

期望的输出结果
onload
init-no-promise
start
(1000) init-promise

实际的输出结果
onload
init-no-promise
(1000) init-promise
start
(图片传不上来)

想请教一下,为什么start方法会被异步的promise所阻碍。

1赞

我特意测了一下,start并没有阻塞

能传上来图了

promise用的不对吧,你这样写,相当于直接在onLoad里面写一个for循环

这样写才对吧:

init() {
    Promise.resolve().then(() => {
        return new Promise((resolve) => {
            let count = 0
            this.schedule(() => {
                cc.log("init-promise")
                count++
                if (count === 10) {
                    resolve();
                }
            }, 1, 10)
        })
    }).then(() => {
        cc.log("finish")
    })
    cc.log("init-no-promise")
}

你的代码主要是使用了schedule而完成的异步 并不是使用promise完成的异步

??? finish

你将你代码中的schedule去掉 依然是阻塞的

正确用法

async init() {
for (let i = 0; i < 10; i++) {
await this.callfunc();
}
cc.log(“init-no-promise”)
}

callfunc() {
    return new Promise((resolve) => {
        setTimeout(() => {
            cc.log("init-promise");
            resolve();
        }, 1000)

    })
}

… 没区别 你用的setTimeout实现的异步 你把setTimeout去掉了一样是阻塞的

我的问题是 纯promise应该是异步的 但是在引擎中却是一个半同步的

这是我的日志,start先执行,init-no-promise最后执行 没毛病,不跟你纠结了

你并没有理解我核心问题是什么
我的问题是 纯promise应该是异步的 但是在引擎中却是一个半同步的
而你只是通过schedule或者setTimeout来实现的异步,并不是我问的问题。

还是期待大佬来解答这个问题吧。

因为 start 方法是由引擎的 mainLoop 方法所驱动的,而 mainLoop是由一个 requestAnimationFrame所驱动。

setTimeout(0), promise这些是由类似micro task的机制异步执行的,而requestAnimationFrame是浏览器下次repaint才会去触发 。一般来说触发的间隔是每秒60次。

不能保证 requestAnimationFrame和micro task的执行顺序,大多数情况下,可能是先 micro task – micro task --> animationFrame 这样的顺序。 但是spec里面没有说明浏览器要严格执行什么顺序。

4赞

原来如此 感谢大佬的解答