J'implémente une fonction de rendu personnalisée pour marqué qui vérifiera un quelques conditions sur les images, fait une requête asynchrone puis renvoie une image d'une autre source. Cependant, comme la nouvelle requête est asynchrone, je ne recevrai jamais qu'une promesse au lieu d'une "vraie" URL d'image.
attachmentService.getBlobUrl est une fonction async qui fait une requête http et retourne une promesse.
Ma fonction de rendu ressemble à ceci:
// ...
return (async () => {
return await this.attachmentService.getBlobUrl(attachment)
.then(url => {
return `<img src="${url}" alt="${text}" title="${title}"/>`
})
})()
// ...
J'ai déjà essayé de renvoyer la balise d'image directement:
// ...
return this.attachmentService.getBlobUrl(attachment)
.then(url => {
return `<img src="${url}" alt="${text}" title="${title}"/>`
})
// ...
3 Réponses :
la fonction de rendu elle-même doit être synchrone
Ensuite, il n'est pas possible d'utiliser une fonction asynchrone comme getBlobUrl ici. Vous ne pouvez jamais faire ce travail, c'est complètement impossible.
Au lieu de cela, vous devrez repenser votre approche. Évaluez les conditions et effectuez les requêtes asynchrones avant d'appeler marqué . Ensuite, transmettez les données que vous pouvez rendre de manière synchrone.
Faire des demandes pour obtenir les données avant n'est pas vraiment possible car je ne sais pas ce que je demande que je dois faire au préalable
Vous pouvez différer votre opération asynchrone:
classe unique aux éléments img qui doivent être traités différemment. Vous pouvez également changer l'attribut src en une image de chargement. MutationObserver et n'écoutez que les éléments ajoutés. Dans le callback du MutationObserver, vous pouvez ensuite effectuer votre opération asynchrone et mettre à jour le src de l'élément.
C'est un peu ce que j'ai fini par faire. Je n'ai pas ajouté de MutationObserver mais j'ai plutôt modifié l'élément src de img directement. Le tout dans this. $ NextTick () de Vuejs qui garantit que les modifications sont apportées avant que les éléments ne soient rendus.
Voir ma réponse ci-dessous pour référence complète
J'ai fini par ajouter une nouvelle classe aux éléments img nécessitant un traitement spécial et les ai bouclés après la compilation de la démarque en html:
marked.use({
renderer: {
image: (src, title, text) => {
title = title ? ` title="${title}` : ''
if (someCondition) {
return `<img data-src="${src}" alt="${text}" ${title} class="attachment-image"/>`
}
return `<img src="${src}" alt="${text}" ${title}/>`
},
}
})
this.preview = DOMPurify.sanitize(marked(this.text))
// Since the render function is synchronous, we can't do async http requests in it.
// Therefore, we can't resolve the blob url at (markdown) compile time.
// To work around this, we modify the url after rendering it in the vue component.
// We're doing the whole thing in the next tick to ensure the image elements are
// available in the dom tree. If we're calling this right after setting this.preview
// it could be the images were already made available.
this.$nextTick(() => {
document.getElementsByClassName('attachment-image').forEach(img => {
// ...
// some code ...
// ...
this.attachmentService.getBlobUrl(attachment)
.then(url => {
img.src = url
})
})
})
Après une recherche rapide: les moteurs de rendu asynchrones ne sont pas pris en charge ( github.com/markedjs/marked/issues/458 ) Vous devrez donc écrire votre moteur de rendu personnalisé de manière synchrone.
@slhilch Mais comment retournerais-je le résultat d'une fonction asynchrone à l'intérieur de cette fonction de rendu synchrone?
Je ne pense pas que vous puissiez faire ça en Javascript. Vous devrez également écrire ce synchrone
getBlobUrl.getBlobUrlest une requête http et, de par sa conception, asynchrone. J'ai peur de ne pas pouvoir le rendre synchrone. Alors pas de chance?Vous pouvez faire des requêtes HTTP synchrones mais elles sont obsolètes: développeur .mozilla.org / en-US / docs / Web / API / XMLHttpRequest /…