diff --git a/src/mol-util/data-source.ts b/src/mol-util/data-source.ts index c66d6c68c8b760d639c1ef40788f093d8bfb7ef7..7f4999661034caa719adb1b207b8184e9e5d2777 100644 --- a/src/mol-util/data-source.ts +++ b/src/mol-util/data-source.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -67,8 +67,8 @@ function decompress(buffer: Uint8Array): Uint8Array { // return gzip.decompress(); } -async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compressed: boolean, e: any) { - const data = (e.target as FileReader).result; +async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compressed: boolean, fileReader: FileReader) { + const data = fileReader.result; if (compressed) { await ctx.update('Decompressing...'); @@ -84,11 +84,31 @@ async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compresse } } -function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | FileReader, asUint8Array: boolean): Promise<any> { - return new Promise<any>((resolve, reject) => { - data.onerror = (e: any) => { +function isDone(data: XMLHttpRequest | FileReader) { + if (data instanceof FileReader) { + return data.readyState === FileReader.DONE + } else if (data instanceof XMLHttpRequest) { + return data.readyState === XMLHttpRequest.DONE + } + throw new Error('unknown data type') +} + +function readData<T extends XMLHttpRequest | FileReader>(ctx: RuntimeContext, action: string, data: T, asUint8Array: boolean): Promise<T> { + return new Promise<T>((resolve, reject) => { + // first check if data reading is already done + if (isDone(data)) { + const error = (<FileReader>data).error; + if (error) { + reject((<FileReader>data).error || 'Failed.'); + } else { + resolve(data); + } + return + } + + data.onerror = (e: ProgressEvent) => { const error = (<FileReader>e.target).error; - reject(error ? error : 'Failed.'); + reject(error || 'Failed.'); }; let hasError = false; @@ -106,7 +126,10 @@ function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | Fi reject(e); } } - data.onload = (e: any) => resolve(e); + + data.onload = (e: ProgressEvent) => { + resolve(data); + } }); } @@ -121,8 +144,8 @@ function readFromFileInternal(file: File, asUint8Array: boolean): Task<string | else reader.readAsBinaryString(file); ctx.update({ message: 'Opening file...', canAbort: true }); - const e = await readData(ctx, 'Reading...', reader, asUint8Array); - const result = processFile(ctx, asUint8Array, isCompressed, e); + const fileReader = await readData(ctx, 'Reading...', reader, asUint8Array); + const result = processFile(ctx, asUint8Array, isCompressed, fileReader); return result; } finally { reader = void 0; @@ -156,27 +179,25 @@ class RequestPool { } } -async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompressGzip: boolean, e: any) { - const req = (e.target as XMLHttpRequest); +async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompressGzip: boolean, req: XMLHttpRequest) { if (req.status >= 200 && req.status < 400) { - if (asUint8Array) { - const buff = new Uint8Array(e.target.response); - RequestPool.deposit(e.target); + if (asUint8Array === true) { + const buff = new Uint8Array(req.response); + RequestPool.deposit(req); if (decompressGzip) { return decompress(buff); } else { return buff; } - } - else { - const text = e.target.responseText; - RequestPool.deposit(e.target); + } else { + const text = req.responseText; + RequestPool.deposit(req); return text; } } else { const status = req.statusText; - RequestPool.deposit(e.target); + RequestPool.deposit(req); throw status; } } @@ -196,23 +217,23 @@ function ajaxGetInternal(title: string | undefined, url: string, type: 'json' | xhttp.send(body); await ctx.update({ message: 'Waiting for server...', canAbort: true }); - const e = await readData(ctx, 'Downloading...', xhttp, asUint8Array); - xhttp = void 0; - const result = await processAjax(ctx, asUint8Array, decompressGzip, e) + const req = await readData(ctx, 'Downloading...', xhttp, asUint8Array); + xhttp = void 0; // guard against reuse, help garbage collector + const result = await processAjax(ctx, asUint8Array, decompressGzip, req) if (type === 'json') { await ctx.update({ message: 'Parsing JSON...', canAbort: false }); - return JSON.parse(result); + return JSON.parse(result as string); } else if (type === 'xml') { await ctx.update({ message: 'Parsing XML...', canAbort: false }); - return parseXml(result); + return parseXml(result as string); } return result; }, () => { if (xhttp) { xhttp.abort(); - xhttp = void 0; + xhttp = void 0; // guard against reuse, help garbage collector } }); }