-
-
Notifications
You must be signed in to change notification settings - Fork 143
Open
Labels
Description
I'd like to fetch documents and includes asynchronously (in-browser), using fetch
.
By default, it uses synchronous XMLHttpRequest, which locks the browser and also give us a warning:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help http://xhr.spec.whatwg.org/ asciidoctor.js:23436:8
That's why I'd like to suggest a loadAsync / convertAsync API for Asciidoctor.js.
Perhaps a related suggestion is a way for the user to specify their own http client, e.g. if someone wishes to use fetch, axios, or node-fetch.
As a really convoluted work-around / proof-of-concept, I've managed to use two include processor extensions and Promises to progressively "load" the document. Right now this will only go down to one level of includes. There are a number of other issues of course, but primarily is that it's loading/parsing the document more than once.
const asciidoctor = Asciidoctor();
const root = document.getElementById('root');
function promiseObject(object) {
let promisedProperties = [];
const objectKeys = Object.keys(object);
objectKeys.forEach((key) => promisedProperties.push(object[key]));
return Promise.all(promisedProperties)
.then((resolvedValues) => {
return resolvedValues.reduce((resolvedObject, property, index) => {
resolvedObject[objectKeys[index]] = property;
return resolvedObject;
}, object);
});
}
fetch('index.adoc').then(res => res.text()).then(content => {
const includesMap = {};
const registry1 = asciidoctor.Extensions.create();
registry1.includeProcessor(function () {
var self = this;
self.handles(_ => true);
self.process(function (doc, reader, target, attrs) {
if (!includesMap[target]) includesMap[target] = fetch(target).then(res => res.text());
return reader.pushInclude('pending...', target, target, 1, attrs);
});
});
asciidoctor.load(content, {'safe': 'safe', extension_registry: registry1});
promiseObject(includesMap).then(includes => {
const registry2 = asciidoctor.Extensions.create();
registry2.includeProcessor(function () {
var self = this;
self.handles(_ => true);
self.process(function (doc, reader, target, attrs) {
return reader.pushInclude(includes[target], target, target, 1, attrs);
});
});
const doc = asciidoctor.load(content, {'safe': 'safe', extension_registry: registry2});
const html = doc.convert();
root.innerHTML = html;
});
});
nwittwer