@引擎团队 提一个小建议: Creator源码中个别方法直接返回异步对象可否?

首先我不是来吐槽的,只是弱弱的提几个小小de建议。用了几年的ccc引擎,首先一万个赞,谢谢雅基软件 —— Cocos 引擎官方团队!

有一个问题,需要指出,源码中有几处地方,如果可以优化一下,我认为体验会更好。
1.关于音频管理的对象操作,大部分在于cc.audioEngine中,应该返回Promise对象;

原因:经常出现cc.audioEngine对某一个音频连续的操作,会出现各种诡异异常,我知道是音乐异步导致的,通常在之前加一个延迟10毫秒搞定,比如我经常需要这样的操作:

async pauseInnerAudio() {
        if(this._currAudioId === null) {
            return;
        }
        await TimeUtil.waitSeconds(10);//故意延迟一点,否则此方法执行完立即执行其他操作,音频会异常
        let isPause = cc.audioEngine.pause(this._currAudioId);
        await TimeUtil.waitSeconds(10);//故意延迟一点,否则此方法执行完立即执行其他操作,音频会异常
        cc.log("暂停当前的音效isPause:",isPause,this._currAudioId);
    }

    async resumeInnerAudio() {
        if(this._currAudioId === null) {
            return Promise.reject(`「this._currAudioId==null」`);
        }
        await TimeUtil.waitSeconds(10);//故意延迟一点,否则此方法执行完立即执行其他操作,音频会异常
        let isResume = cc.audioEngine.resume(this._currAudioId);
        await TimeUtil.waitSeconds(10);//故意延迟一点,否则此方法执行完立即执行其他操作,音频会异常
        cc.log("继续当前的音效isResume:",isResume,this._currAudioId);
    }

2.关于cc.Widget / cc.Layout 也是有存在异步的行为,如果忽视了异步,立即执行一些操作的时候,往往也会出现比较奇怪的现象,比如下面的问题,我就发现了:

https://forum.cocos.com/t/cc-widget-updatealignment-bug-ccc2-1-2/82929


3.有一些文件操作也同样是异步的,我相信如果使用Promise操作会比引擎现在所使用的回调会更直观,比如wxDownloader中增加一些修改:

    /**
         * 解压 zip文件到 wx.env.USER_DATA_PATH目录
         * @param {string} filePath 
         * @param {{onZipProgress:Function,status:number}} taskReporter 
         */
        toUnzip(filePath,targetDir,taskReporter) {
            let path = wx.env.USER_DATA_PATH;
            if(targetDir) {
                path = path + "/" + targetDir;
            }
            let sequence = new Promise(resolve=>{
                let fileManager = wx.getFileSystemManager();
                fileManager.unzip({
                    zipFilePath: filePath,   // 资源下载后路径
                    targetPath: path,  // 解压资源存放路径
                    success:(res)=>{// 解压成功
                        console.log("解压成功");
                        if(taskReporter && taskReporter.onZipProgress) {
                            taskReporter.onZipProgress(100,1);
                        }
                        resolve(true);
                    },
                    fail:(res)=>{// 解压失败
                        ++this._unzipCount;
                        console.log("解压失败:",filePath,path,JSON.stringify(res));
                        resolve(false);
                    },
                });
            });
            sequence = sequence.then(isOk=>{
                if(this._unzipCount > 10) {
                    console.log(`解压了10次失败.`);
                    return Promise.resolve(false);
                }
                if(!isOk) {
                    return this.toUnzip(filePath,targetDir,taskReporter);
                }
            });
            return sequence;
        }

/**
     * 删除指定位置的文件
     * @param {string} filePath 
     */
    deleteFile(filePath) {
        return new Promise((resolve,reject)=>{
            wx.getFileSystemManager().unlink({
                filePath: filePath,
                success: _=>{
                    console.log('Removed local file ' + filePath + ' successfully!');
                    resolve();
                },
                fail: res=>{
                    console.warn(res.errMsg);
                    reject(res.errMsg);
                }
            });
        });
    }

    /**
     * 根据指定路径,创建目录
     * @param {string} dirPath 
     */
    makeDir(dirPath) {
        let sequence =  this.fileAccess(dirPath);
        sequence = sequence.then(isExist=>{
            if(!isExist) {
                return new Promise(resolve=>{
                    wx.getFileSystemManager().mkdir({
                        dirPath: wx.env.USER_DATA_PATH + '/' + dirPath,
                        encoding: 'utf8',
                        success: res=>{
                            resolve(true);
                        },
                        fail: res=>{
                            resolve(false);
                        }});
                });
            }else {
                return Promise.resolve(isExist);
            }
        }); 
        sequence = sequence.then(isOk=>{
            if(!isOk) {
                return this.makeDir(dirPath);
            }
        });
        return sequence;
    }

主要是前2个,因为改动比较麻烦,最后一个倒无所谓,问题不大。

补充一点:我知道,源码中异步多了,因为代码调用的各种可能性,同步和异步经常会导致其他的异常,比如最典型的"空指针异常",无疑会增加不少开发量,以及测试的工作量,异步能少用就少用,只在几个关键点上用;所以,我只是提个建议,引擎团队自己衡量。

4赞

支持Promise

沉了这么久,竟然被你顶了一下,感谢支持。不过估计也没什么人看。

let newFn = (a,b,c)=>{ return new Promise( (resolve,reject)=> { oldFn(a,b,c,success(){ resolve([null,“result”]) },failed(err){ resolve([err,null])}) })}

一句话重新包装一下就行了,自给自足,很多人家的老旧代码都是callback型的,自己包一下就好,毕竟es6的语法还是很方便的
有时候为了方便也这样写,反正很爽:
let [err,data] = await new Promise( (resolve,reject)=> { oldFn(“args1”,“args2”,“args3”,success(){ resolve([null,“result”]) },failed(err){ resolve([err,null])}) })

自己的代码随便想怎么写就怎么写。

我想讨论的是官方引擎内部的代码。

官方好像creator 3D全面用了Promise,遗留的估计难了

收到,谢谢反馈,已经记录到排期

:14::14::14:

Promise IE 支持吗?

自己封装下吧,用到的自己封装下