0
votes

retourne le résultat de la fonction asynchrone dans la fonction synchrone

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}"/>`
    })
// ...


5 commentaires

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 .


getBlobUrl est 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 /…


3 Réponses :


0
votes

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.


1 commentaires

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



1
votes

Vous pouvez différer votre opération asynchrone:

  1. Dans votre moteur de rendu personnalisé, ajoutez simplement un nom de 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.
  2. Ensuite, avant que l'un de ces éléments ne soit rendu, créez un 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.

2 commentaires

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



0
votes

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
            })
    })
})


0 commentaires