66666!
做大做强~yeah
还是你会取标题,看见包教包会,我就进来了
Promise 时序差异
由于 iOS JavaScriptCore 的限制,iOS 15 及以下的 Promise 是一个使用 setTimeout 模拟的 Polyfill。这意味着 Promise 触发的任务为普通任务,而非微任务,进而导致 在 iOS15 及以下的 Promise 时序会和标准存在差异 。
iOS 16 及以上不存在差异。
var arr = []
setTimeout(() => arr.push(6), 0)
arr.push(1)
const p = new Promise(resolve => {
arr.push(2)
resolve()
})
arr.push(3)
p.then(() => arr.push(5))
arr.push(4)
setTimeout(() => arr.push(7), 0)
setTimeout(() => {
// 应该输出 [1,2,3,4,5,6,7]
// 在 iOS15 小程序环境,这里会输出 [1,2,3,4,6,5,7]
console.log(arr)
}, 1000)
关于普通任务和微任务的区别可以查看这篇文章
把这一节教懂学懂,才属于包教包会
可以,你的帖子我都不用在收藏找,太好搜了。(吐槽下,收藏的功能要用的时候基本找不到
)
跟营销号学的,还可以吧? 
可以可以,我这个是入门版,你是进阶版
必须的,相当于品牌商标
学到了,学到了。以后资源加载这块就很nice 了
继续对应下具体业务中会遇到什么问题吗? 感觉遇到就是个坑.
最近正在用Promise做一个加载模块图集中素材的接口,做了作业练习了一下。
/**
* 异步加载指定路径的资源并执行回调函数
* @template LoadType 资源类型构造函数,必须继承自 cc.Asset
* @template CallbackResult 回调函数的返回类型
* @param {string} path 资源路径,格式为"bundle名称/资源路径"
* @param {LoadType} type 要加载的资源类型(构造函数)
* @param {(asset: InstanceType<LoadType>) => CallbackResult} callback 加载完成后执行的回调函数(参数为资源实例)
* @returns {Promise<CallbackResult>} 返回包含回调结果的Promise
* @throws {Error} 当加载bundle或资源失败时抛出错误
* @deprecated 未对资源进行引用计数管理
* @example
* loadAsset2('resources/Texture/Images/imageName', cc.SpriteFrame, (loadAssert): void => {
this.testLoadSprite.spriteFrame = loadAssert
})
*/
async function loadAsset2<LoadType extends typeof Asset, CallbackResult>(
path: string,
type: LoadType,
callback: (asset: InstanceType<LoadType>) => CallbackResult
): Promise<CallbackResult> {
const slashIndex: number = path.indexOf('/');
const bundleName: string = path.slice(0, slashIndex);
const assetPath: string = path.slice(slashIndex + 1);
// 加载bundle
const bundle: AssetManager.Bundle = await new Promise<AssetManager.Bundle>((resolve, reject) => {
assetManager.loadBundle(bundleName, (err: Error, bundle: AssetManager.Bundle): void => {
if (err) reject(err);
else resolve(bundle);
});
});
// 加载资源
const asset: InstanceType<LoadType> = await new Promise<InstanceType<LoadType>>((resolve, reject) => {
bundle.load(assetPath, type, (err: Error, loadedAsset: InstanceType<LoadType>): void => {
if (err) reject(err);
else resolve(loadedAsset);
});
});
// 执行回调
return callback(asset);
}
优点:做了泛型,类型更安全
缺点:这个方法取的是资源因此不需要resolve(bundle),异步方法无需callback直接resolve(asset)
如果是要显示加载进度还是需要回调的
加载单个资源进度获取不到吧,加载bundle可以取到的
其实使用await也要小心,当你的view被干掉了,但是你的delay还没有被清掉,时间到了会继续执行后面的代码,这个this已经无效了
const weakMap = new WeakMap(); // 全局弱引用映射
if (CC_DEV) {
window["my_weakMap "] = weakMap
}
const thenFunc = Promise.prototype.then
Promise.prototype.then = function (onFulfilled, onRejected) {
const that = this
return thenFunc.call(this,
function (value) {
if (typeof onFulfilled === 'function') {
const targetRef = weakMap .get(that);
if (targetRef && !cc.isValid(targetRef)) {
console.warn('Promise liftTarget Component is invalid, skip then callback')
// onRejected?.("liftTarget this is valid")
return;
}
return onFulfilled(value)
}
return value;
},
onRejected)
}
Promise.prototype.isValid= function (target: cc.Node | cc.Component) {
if (!target) return this;
weakMap .set(this, target); // 键是 Promise 实例,值是被弱引用的 target
return this;
}
declare global {
/**全局hook */
interface Promise<T> {
/**处理异步后生命周期问题 */
isValid: (target: cc.Component | cc.Node) => Promise<any>
}
}
//使用示例
await this.delay(100).isVaild(this) //当this 无效后 不会执行后面代码了
后来为了弄这个,我新增了isVaild方法,AI说尽量不这样扩展,但是这是改动已有代码的无二选择了,不然得在所有的await地方去判断 this是不是null,是不是还有效
该代码已经上线运行了,目前没什么问题
嗯,异步是会有这个问题
当初这样写了,AI这样说过 改动太多了 莫法
受限当前业务中 只有一层的then,所以还好 可以在失效的时候 return value出去, 业务底层都是使用的resolve(null) 来处理错误 所以不存在reject的问题,可以根据自己的情况改动
还是因为js的promise没有中断,不然全局处理下就行了~
是的,它本身没有提供 ,不管使用第三方或者使用代理的形式,都会在其他使用的地方大量穿插


