165 lines
5.0 KiB
Plaintext
165 lines
5.0 KiB
Plaintext
|
||
// 1. TextDecoder -
|
||
// 2. TextDecoder's stream option (Firefox 38 + - how to detect ?) -
|
||
// 3. Promise.prototype.finally -
|
||
// 4. fetch +
|
||
// 5. Response.prototype.body +
|
||
// 6. ReadableStream.prototype.getReader (no Firefox support yet) +
|
||
// 7. AbortController (Firefox 57) +
|
||
|
||
var s = "";
|
||
if (window.Uint8Array != null && window.TextDecoder != null) {
|
||
var b = function (byte) {
|
||
var x = new Uint8Array(1);
|
||
x[0] = byte;
|
||
return x;
|
||
};
|
||
var textDecoder = new TextDecoder();
|
||
var chunk = textDecoder.decode(b(208), {stream: true}) + textDecoder.decode(b(176), {stream: true});
|
||
s = chunk;
|
||
};
|
||
|
||
console.log('TextDecoder', typeof window.TextDecoder);
|
||
console.log('TextDecoder+stream', chunk === 'а');
|
||
console.log('Promise#finally', window.Promise != null ? typeof window.Promise.prototype.finally : typeof undefined);
|
||
console.log('fetch', typeof window.fetch);
|
||
console.log('Response#body', window.Response != null && 'body' in window.Response.prototype);
|
||
console.log('ReadableStream#getReader', window.ReadableStream != null ? typeof window.ReadableStream.prototype.getReader : typeof undefined);
|
||
console.log('AbortController', typeof window.AbortController);
|
||
|
||
// an example from https://fetch.spec.whatwg.org/
|
||
var url = 'https://matrixcalc.org/jstest/tests.php?events';
|
||
|
||
function consume(reader) {
|
||
var responseText = '';
|
||
var pump = function () {
|
||
return reader.read().then(function (result) {
|
||
if (result.done) {
|
||
console.log('responseText', responseText);
|
||
return;
|
||
}
|
||
responseText += String.fromCharCode.apply(undefined, result.value);
|
||
return pump();
|
||
});
|
||
};
|
||
return pump();
|
||
}
|
||
|
||
if (window.fetch != null && window.TextDecoder != null) {
|
||
fetch(url).then(function (response) {
|
||
var body = response.body;
|
||
console.log('response.body', typeof body);
|
||
if (body != null) {
|
||
console.log('response.body.getReader', typeof body.getReader);
|
||
if (typeof body.getReader == 'function') {
|
||
consume(body.getReader());
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
setTimeout(function () {
|
||
console.log('done');
|
||
}, 1000);
|
||
|
||
|
||
|
||
|
||
// Firefox < 38 (no "stream" option), IE, Edge
|
||
function TextDecoderPolyfill() {
|
||
}
|
||
|
||
//TODO: streaming
|
||
TextDecoderPolyfill.prototype.decode = function (octets) {
|
||
var string = "";
|
||
var i = 0;
|
||
while (i < octets.length) {
|
||
var octet = octets[i];
|
||
var bytesNeeded = 0;
|
||
var codePoint = 0;
|
||
if (octet <= 0x7F) {
|
||
bytesNeeded = 0;
|
||
codePoint = octet & 0xFF;
|
||
} else if (octet <= 0xDF) {
|
||
bytesNeeded = 1;
|
||
codePoint = octet & 0x1F;
|
||
} else if (octet <= 0xEF) {
|
||
bytesNeeded = 2;
|
||
codePoint = octet & 0x0F;
|
||
} else if (octet <= 0xF4) {
|
||
bytesNeeded = 3;
|
||
codePoint = octet & 0x07;
|
||
}
|
||
if (octets.length - i - bytesNeeded > 0) {
|
||
var k = 0;
|
||
while (k < bytesNeeded) {
|
||
octet = octets[i + k + 1];
|
||
codePoint = (codePoint << 6) | (octet & 0x3F);
|
||
k += 1;
|
||
}
|
||
} else {
|
||
codePoint = 0xFFFD;
|
||
bytesNeeded = octets.length - i;
|
||
}
|
||
string += String.fromCodePoint(codePoint);
|
||
i += bytesNeeded + 1;
|
||
}
|
||
return string
|
||
};
|
||
|
||
// ?
|
||
if (Promise != undefined && Promise.prototype["finally"] == undefined) {
|
||
Promise.prototype["finally"] = function (callback) {
|
||
return this.then(function (result) {
|
||
return Promise.resolve(callback()).then(function () {
|
||
return result;
|
||
});
|
||
}, function (error) {
|
||
return Promise.resolve(callback()).then(function () {
|
||
throw error;
|
||
});
|
||
});
|
||
};
|
||
}
|
||
|
||
var open = function (onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers, timeout) {
|
||
// cache: "no-store"
|
||
// https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||
var textDecoder = new TextDecoder();
|
||
fetch(url, {
|
||
headers: headers,
|
||
credentials: withCredentials ? "include" : "same-origin"
|
||
}).then(function (response) {
|
||
var reader = response.body.getReader();
|
||
onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"));
|
||
return new Promise(function (resolve, reject) {
|
||
var readNextChunk = function () {
|
||
var id = setTimeout(function () {
|
||
reader.cancel();
|
||
resolve(undefined);
|
||
}, timeout);
|
||
reader.read().then(function (result) {
|
||
clearTimeout(id);
|
||
if (result.done) {
|
||
//Note: bytes in textDecoder are ignored
|
||
resolve(undefined);
|
||
} else {
|
||
var chunk = textDecoder.decode(result.value, {stream: true});
|
||
//var chunk = String.fromCharCode.apply(undefined, result.value);
|
||
onProgressCallback(chunk);
|
||
readNextChunk();
|
||
}
|
||
})["catch"](function (error) {
|
||
clearTimeout(id);
|
||
reject(error);
|
||
});
|
||
};
|
||
readNextChunk();
|
||
});
|
||
})["finally"](function () {
|
||
onFinishCallback();
|
||
});
|
||
};
|
||
|
||
|