gpt4 book ai didi

Angular 4.x + Cordova : FileReader fails silently (white screen of death)

转载 作者:太空狗 更新时间:2023-10-29 18:08:14 27 4
gpt4 key购买 nike

我有一个 Angular 4.3 + Cordova 应用程序,它曾经运行良好。但是现在,我在应用程序启动时出现了一个空白屏幕,再也没有任何反应。

经过一段时间的挖掘,我意识到它来自哪里:

我的主页受 CanActivate 守卫保护,它会检查一些文件系统持久化的首选项,如果这是第一次运行或缺少所需的首选项,则将用户重定向到另一个页面,填写所需的属性。

所以应用程序的启动取决于我的 CanActivate 守卫,它依赖于 PreferenceService 而它本身又依赖于我自己实现的 FileSystemService .问题是,当我尝试读取存储用户首选项的文件时,没有触发任何回调,什么也没有发生,甚至没有错误

这是我的 FileSystemService 没有任何错误的部分:

read(file: FileEntry, mode: "text" | "arrayBuffer" | "binaryString" | "dataURL" = "text"): Observable<ProgressEvent> {
return this.cdv.ready.flatMap(() => {
return Observable.create(observer => {
file.file(file => {
let reader = new FileReader();
reader.onerror = (evt: ErrorEvent) => {
this.zone.run(() => observer.error(evt)); //never triggered
};
reader.onload = (evt: ProgressEvent) => {
this.zone.run(() => observer.next(evt)); //never trigerred
};
switch (mode) {
case "text":
reader.readAsText(file);
break;
case "arrayBuffer":
reader.readAsArrayBuffer(file);
break;
case "binaryString":
reader.readAsBinaryString(file);
break;
case "dataURL":
reader.readAsDataURL(file);
break;
}
});
});
});
}

为什么会发生这种情况,我该如何处理才能触发我的回调?

最佳答案

编辑

如前所述,我在 zone.js 存储库上提出了一个问题,zone.js 所有者迅速修补了代码。您可以通过在 polyfill 中导入 zone.js/zone-patch-cordova 来避免使用我的肮脏 hack 的痛苦。

原始答案

在调试此代码时,我意识到 FileReader 构造函数已被 cordova 和 zone.js 修补。根据我对 zone.js 补丁的理解,它会将每个“onProperty”(onloadonloadendonerror)更改为其 addEventListener(...) 计数器部分。

Module Name:

on_property

Behavior with zone.js :

target.onProp will become zone aware target.addEventListener(prop)

source

但是cordova没有使用dispatchEvent(...) API来通知监听器操作已经结束。

一个解决方案可能是从 zone.js 中停用 onProperty 模块,但它可能会破坏 Angular 的行为

这就是我应对这种情况的方式:

read(file: FileEntry, mode: "text" | "arrayBuffer" | "binaryString" | "dataURL" = "text"): Observable<ProgressEvent> {
return this.cdv.ready.flatMap(() => {
return Observable.create(observer => {
file.file(file => {
let FileReader: new() => FileReader = ((window as any).FileReader as any).__zone_symbol__OriginalDelegate
let reader = new FileReader();
reader.onerror = (evt: ErrorEvent) => {
this.zone.run(() => observer.error(evt)); //never triggered
};
reader.onload = (evt: ProgressEvent) => {
this.zone.run(() => observer.next(evt)); //never trigerred
};
switch (mode) {
case "text":
reader.readAsText(file);
break;
case "arrayBuffer":
reader.readAsArrayBuffer(file);
break;
case "binaryString":
reader.readAsBinaryString(file);
break;
case "dataURL":
reader.readAsDataURL(file);
break;
}
});
});
});
}

这里的 secret 是 zone.js 将原始构造函数保留在 __zone_symbol__OriginalDelegate 属性中,因此调用它实际上会直接调用 Cordova 的 FileReader 而无需 zone.js补丁

这个解决方案是一个肮脏的黑客,我有 openned an issue on zone's repository

编辑:

FileWriter 有同样的问题(它在内部调用一个FileReader)所以我写了这个小垫片:

function noZonePatch(cb: () => void) {
const orig = FileReader;
const unpatched = ((window as any).FileReader as any).__zone_symbol__OriginalDelegate;
(window as any).FileReader = unpatched;
cb();
(window as any).FileReader = orig;
}

然后包装我对读/写操作的调用:

write(file: FileEntry, content: Blob) {
return this.cdv.ready.flatMap(() => {
return Observable.create((out: Observer<ProgressEvent>) => {
file.createWriter((writer) => {
noZonePatch(() => {
writer.onwrite = (evt: ProgressEvent) => {
this.zone.run(() => {
out.next(evt);
out.complete();
});
};
writer.onerror = (evt) => {
this.zone.run(() => out.error(evt));
};
writer.write(content); // this is where FileReader is called internally
})
}, err => out.error(err));
});
});
}

read(file: FileEntry, mode: ReadMode = "text"): Observable<ProgressEvent> {
return this.cdv.ready.switchMap(() => Observable.create((observer: Observer<ProgressEvent>) => {
file.file(file => {
noZonePatch(() => {
let reader = new FileReader();
reader.onerror = (evt: ErrorEvent) => {
this.zone.run(() => observer.error(evt));
};
reader.onload = (evt: ProgressEvent) => {
this.zone.run(() => observer.next(evt));
};
switch (mode) {
case "text":
reader.readAsText(file);
break;
case "arrayBuffer":
reader.readAsArrayBuffer(file);
break;
case "binaryString":
reader.readAsBinaryString(file);
break;
case "dataURL":
reader.readAsDataURL(file);
break;
}
});
});
}));
}

关于 Angular 4.x + Cordova : FileReader fails silently (white screen of death),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45542462/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com