0

我正在为标记实现一个自定义渲染函数,它将检查图像的一些条件,执行异步请求,然后从不同的源返回图像。然而,由于新请求是异步的,我只会得到一个承诺,而不是一个“真实的”图像 url。

attachmentService.getBlobUrl是一个异步函数,它执行一个 http 请求并返回一个承诺。

我的渲染函数如下所示:

marked.use({
    renderer: {
        image: (src, title, text) => {
            if (someCondition) {

                // Some code of parsing the src attribute
                // ...

                return this.attachmentService.getBlobUrl(attachment)
                    .then(url => {
                        return Promise.resolve(`<img src="${url}" alt="${text}" title="${title}"/>`)
                    })
            }

            return `<img src="${src}" alt="${text}" title="${title}"/>`
        },
    }
})

我已经尝试直接返回图像标签:

// ...
return this.attachmentService.getBlobUrl(attachment)
    .then(url => {
        return `<img src="${url}" alt="${text}" title="${title}"/>`
    })
// ...

我还尝试将函数包装在async调用中并返回(未包装在 a 中Promise.resolve):

// ...
return (async () => {
    return await this.attachmentService.getBlobUrl(attachment)
        .then(url => {
            return `<img src="${url}" alt="${text}" title="${title}"/>`
        })
})()
// ...

然而,这也只是给了我一个承诺。

我不能使用await,因为渲染函数本身必须是同步的——这不是我可以控制的。

4

3 回答 3

1

您可以推迟异步操作:

  1. class在您的自定义渲染器中,只需为应该区别对待的 img 元素添加一些唯一名称。您还可以将src属性更改为某些加载图像。
  2. 然后,在这些元素中的任何一个被渲染之前,创建一个MutationObserver并且只监听这些元素被添加。在 MutationObserver 的回调中,您可以执行异步操作并更新元素的src.
于 2020-07-13T06:43:18.010 回答
0

我最终为需要特殊处理class的元素添加了一个新img元素,并在 markdown 编译为 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
            })
    })
})

这发生在渲染this.previewv-html元素的 vue js 组件中。

需要调用它this.$nextTick以确保img元素可用,以便对它们进行修改。

这个解决方案有点像@shilch 提出的,但我想更多的是“vue-y”。

于 2020-07-13T07:51:41.993 回答
0

渲染函数本身必须是同步的

那么就不可能像getBlobUrl那里那样使用异步函数。你永远无法完成这项工作,这是完全不可能的。

相反,您将需要重新设计您的方法。在调用之前评估条件并执行异步请求marked。然后传入可以同步渲染的数据。

于 2020-07-12T20:27:39.710 回答