Prechádzať zdrojové kódy

Task state and error handling

A task now has an abstract class from which every task extends. This
class has a state object - INIT, RUNNING, DONE and ERROR.  Also, a new
errorObject was added, in case an error occures. This was done due to
the observers' architecture, which prevents us from passing more than
one variable to the callback.

A task can have en ERROR state, but still be done, if the onSuccess
callback had an exception in it. This is why isCompleted is still very
important and should be used.

The assets manager now uses those callbacks, and also reports errors, in
case they were executed during the onFinish callback.

Not a breaking change, but should be noticed - the run function is now
only implemented one time (in the abstract class) the rest have a
runTask function, which actually runs the code. The run function is
executing the local runTask method. This was done to keep backwards
compatibility.
Raanan Weber 7 rokov pred
rodič
commit
a7ab653922
1 zmenil súbory, kde vykonal 126 pridanie a 127 odobranie
  1. 126 127
      src/Tools/babylon.assetsManager.ts

+ 126 - 127
src/Tools/babylon.assetsManager.ts

@@ -1,143 +1,160 @@
 module BABYLON {
 module BABYLON {
+
+    export enum AssetTaskState {
+        INIT,
+        RUNNING,
+        DONE,
+        ERROR
+    }
+
     export interface IAssetTask {
     export interface IAssetTask {
         onSuccess: (task: IAssetTask) => void;
         onSuccess: (task: IAssetTask) => void;
         onError: (task: IAssetTask, message?: string, exception?: any) => void;
         onError: (task: IAssetTask, message?: string, exception?: any) => void;
         isCompleted: boolean;
         isCompleted: boolean;
 
 
-        run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void);
+        taskState: AssetTaskState;
+        errorObject: {
+            message?: string;
+            exception?: any;
+        }
+
+        runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void);
+    }
+
+    export abstract class AbstractAssetTask implements IAssetTask {
+
+        constructor() {
+            this.taskState = AssetTaskState.INIT;
+        }
+
+        onSuccess: (task: IAssetTask) => void;
+        onError: (task: IAssetTask, message?: string, exception?: any) => void;
+
+        isCompleted: boolean = false;
+        taskState: AssetTaskState;
+        errorObject: { message?: string; exception?: any; };
+
+        run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+            this.taskState = AssetTaskState.RUNNING;
+            this.runTask(scene, () => {
+                this.onDoneCallback(onSuccess, onError);
+            }, (msg, exception) => {
+                this.onErrorCallback(onError, msg, exception);
+            });
+        }
+
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+            throw new Error("runTask is not implemented");
+        }
+
+        private onErrorCallback(onError: (message?: string, exception?: any) => void, message?: string, exception?: any) {
+            this.taskState = AssetTaskState.ERROR;
+
+            this.errorObject = {
+                message: message,
+                exception: exception
+            }
+
+            if (this.onError) {
+                this.onError(this, message, exception);
+            }
+
+            onError();
+        }
+
+        private onDoneCallback(onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+            try {
+                this.taskState = AssetTaskState.DONE;
+                this.isCompleted = true;
+
+                if (this.onSuccess) {
+                    this.onSuccess(this);
+                }
+
+                onSuccess();
+            } catch (e) {
+                this.onErrorCallback(onError, "Task is done, error executing success callback(s)", e);
+            }
+        }
+
     }
     }
 
 
-    export class MeshAssetTask implements IAssetTask {
+    export class MeshAssetTask extends AbstractAssetTask implements IAssetTask {
         public loadedMeshes: Array<AbstractMesh>;
         public loadedMeshes: Array<AbstractMesh>;
         public loadedParticleSystems: Array<ParticleSystem>;
         public loadedParticleSystems: Array<ParticleSystem>;
         public loadedSkeletons: Array<Skeleton>;
         public loadedSkeletons: Array<Skeleton>;
 
 
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
-
         constructor(public name: string, public meshesNames: any, public rootUrl: string, public sceneFilename: string) {
         constructor(public name: string, public meshesNames: any, public rootUrl: string, public sceneFilename: string) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene,
             SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene,
                 (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => {
                 (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => {
                     this.loadedMeshes = meshes;
                     this.loadedMeshes = meshes;
                     this.loadedParticleSystems = particleSystems;
                     this.loadedParticleSystems = particleSystems;
                     this.loadedSkeletons = skeletons;
                     this.loadedSkeletons = skeletons;
-
-                    this.isCompleted = true;
-
-                    if (this.onSuccess) {
-                        this.onSuccess(this);
-                    }
-
                     onSuccess();
                     onSuccess();
                 }, null, (scene, message, exception) => {
                 }, null, (scene, message, exception) => {
-                    if (this.onError) {
-                        this.onError(this, message, exception);
-                    }
-
                     onError(message, exception);
                     onError(message, exception);
                 }
                 }
             );
             );
         }
         }
     }
     }
 
 
-    export class TextFileAssetTask implements IAssetTask {
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class TextFileAssetTask extends AbstractAssetTask implements IAssetTask {
         public text: string;
         public text: string;
 
 
         constructor(public name: string, public url: string) {
         constructor(public name: string, public url: string) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             Tools.LoadFile(this.url, (data) => {
             Tools.LoadFile(this.url, (data) => {
-
                 this.text = data;
                 this.text = data;
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             }, null, scene.database, false, (request, exception) => {
             }, null, scene.database, false, (request, exception) => {
-                if (this.onError) {
-                    this.onError(this, request.status + " " + request.statusText, exception);
-                }
-
                 onError(request.status + " " + request.statusText, exception);
                 onError(request.status + " " + request.statusText, exception);
             });
             });
         }
         }
     }
     }
 
 
-    export class BinaryFileAssetTask implements IAssetTask {
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class BinaryFileAssetTask extends AbstractAssetTask implements IAssetTask {
         public data: ArrayBuffer;
         public data: ArrayBuffer;
 
 
         constructor(public name: string, public url: string) {
         constructor(public name: string, public url: string) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             Tools.LoadFile(this.url, (data) => {
             Tools.LoadFile(this.url, (data) => {
 
 
                 this.data = data;
                 this.data = data;
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             }, null, scene.database, true, (request, exception) => {
             }, null, scene.database, true, (request, exception) => {
-                if (this.onError) {
-                    this.onError(this, request.status + " " + request.statusText, exception);
-                }
-
                 onError(request.status + " " + request.statusText, exception);
                 onError(request.status + " " + request.statusText, exception);
             });
             });
         }
         }
     }
     }
 
 
-    export class ImageAssetTask implements IAssetTask {
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class ImageAssetTask extends AbstractAssetTask implements IAssetTask {
         public image: HTMLImageElement;
         public image: HTMLImageElement;
 
 
         constructor(public name: string, public url: string) {
         constructor(public name: string, public url: string) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             var img = new Image();
             var img = new Image();
 
 
             Tools.SetCorsBehavior(this.url, img);
             Tools.SetCorsBehavior(this.url, img);
 
 
             img.onload = () => {
             img.onload = () => {
                 this.image = img;
                 this.image = img;
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             };
             };
 
 
             img.onerror = (err: ErrorEvent): any => {
             img.onerror = (err: ErrorEvent): any => {
-                if (this.onError) {
-                    this.onError(this, "Error loading image", err);
-                }
-
                 onError("Error loading image", err);
                 onError("Error loading image", err);
             };
             };
 
 
@@ -151,33 +168,20 @@
         texture: Texture;
         texture: Texture;
     }
     }
 
 
-    export class TextureAssetTask implements ITextureAssetTask {
-        public onSuccess: (task: ITextureAssetTask) => void;
-        public onError: (task: ITextureAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class TextureAssetTask extends AbstractAssetTask implements ITextureAssetTask {
         public texture: Texture;
         public texture: Texture;
 
 
         constructor(public name: string, public url: string, public noMipmap?: boolean, public invertY?: boolean, public samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
         constructor(public name: string, public url: string, public noMipmap?: boolean, public invertY?: boolean, public samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             };
             };
 
 
             var onerror = (msg, exception) => {
             var onerror = (msg, exception) => {
-                if (this.onError) {
-                    this.onError(this, msg, exception);
-                }
-
                 onError(msg, exception);
                 onError(msg, exception);
             };
             };
 
 
@@ -185,33 +189,20 @@
         }
         }
     }
     }
 
 
-    export class CubeTextureAssetTask implements IAssetTask {
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class CubeTextureAssetTask extends AbstractAssetTask implements IAssetTask {
         public texture: CubeTexture;
         public texture: CubeTexture;
 
 
         constructor(public name: string, public url: string, public extensions?: string[], public noMipmap?: boolean, public files?: string[]) {
         constructor(public name: string, public url: string, public extensions?: string[], public noMipmap?: boolean, public files?: string[]) {
+            super();
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
+        public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             };
             };
 
 
             var onerror = (msg, exception) => {
             var onerror = (msg, exception) => {
-                if (this.onError) {
-                    this.onError(this, msg, exception);
-                }
-
                 onError(msg, exception);
                 onError(msg, exception);
             };
             };
 
 
@@ -219,33 +210,20 @@
         }
         }
     }
     }
 
 
-    export class HDRCubeTextureAssetTask implements IAssetTask {
-        public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
-
-        public isCompleted = false;
+    export class HDRCubeTextureAssetTask extends AbstractAssetTask implements IAssetTask {
         public texture: HDRCubeTexture;
         public texture: HDRCubeTexture;
 
 
         constructor(public name: string, public url: string, public size?: number, public noMipmap = false, public generateHarmonics = true, public useInGammaSpace = false, public usePMREMGenerator = false) {
         constructor(public name: string, public url: string, public size?: number, public noMipmap = false, public generateHarmonics = true, public useInGammaSpace = false, public usePMREMGenerator = false) {
+            super();
         }
         }
 
 
         public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
         public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
-                this.isCompleted = true;
-
-                if (this.onSuccess) {
-                    this.onSuccess(this);
-                }
-
                 onSuccess();
                 onSuccess();
             };
             };
 
 
             var onerror = (message?: string, exception?: any) => {
             var onerror = (message?: string, exception?: any) => {
-                if (this.onError) {
-                    this.onError(this, message, exception);
-                }
-
                 onError(message, exception);
                 onError(message, exception);
             };
             };
 
 
@@ -256,7 +234,7 @@
     export class AssetsManager {
     export class AssetsManager {
         private _scene: Scene;
         private _scene: Scene;
 
 
-        protected tasks = new Array<IAssetTask>();
+        protected tasks = new Array<AbstractAssetTask>();
         protected waitingTasksCount = 0;
         protected waitingTasksCount = 0;
 
 
         public onFinish: (tasks: IAssetTask[]) => void;
         public onFinish: (tasks: IAssetTask[]) => void;
@@ -329,32 +307,53 @@
             this.waitingTasksCount--;
             this.waitingTasksCount--;
 
 
             if (this.waitingTasksCount === 0) {
             if (this.waitingTasksCount === 0) {
-                if (this.onFinish) {
-                    this.onFinish(this.tasks);
+                try {
+                    if (this.onFinish) {
+                        this.onFinish(this.tasks);
+                    }
+
+                    this.onTasksDoneObservable.notifyObservers(this.tasks);
+                } catch (e) {
+                    Tools.Error("Error running tasks-done callbacks.");
+                    console.log(e);
                 }
                 }
 
 
                 this._scene.getEngine().hideLoadingUI();
                 this._scene.getEngine().hideLoadingUI();
             }
             }
         }
         }
 
 
-        private _runTask(task: IAssetTask): void {
-            task.run(this._scene, () => {
-                if (this.onTaskSuccess) {
-                    this.onTaskSuccess(task);
+        private _runTask(task: AbstractAssetTask): void {
+
+            let done = () => {
+                try {
+                    if (this.onTaskSuccess) {
+                        this.onTaskSuccess(task);
+                    }
+                    this.onTaskSuccessObservable.notifyObservers(task);
+                    this._decreaseWaitingTasksCount();
+                } catch (e) {
+                    error("Error executing task success callbacks", e);
+                }
+
+            }
+
+            let error = (message?: string, exception?: any) => {
+                task.errorObject = task.errorObject || {
+                    message: message,
+                    exception: exception
                 }
                 }
-                this.onTaskSuccessObservable.notifyObservers(task);
-                this._decreaseWaitingTasksCount();
-            }, () => {
                 if (this.onTaskError) {
                 if (this.onTaskError) {
                     this.onTaskError(task);
                     this.onTaskError(task);
                 }
                 }
                 this.onTaskErrorObservable.notifyObservers(task);
                 this.onTaskErrorObservable.notifyObservers(task);
                 this._decreaseWaitingTasksCount();
                 this._decreaseWaitingTasksCount();
-            });
+            }
+
+            task.run(this._scene, done, error);
         }
         }
 
 
         public reset(): AssetsManager {
         public reset(): AssetsManager {
-            this.tasks = new Array<IAssetTask>();
+            this.tasks = new Array<AbstractAssetTask>();
             return this;
             return this;
         }
         }