异步函数中异步函数的返回结果

时间:2020-07-12 18:43:33

标签: javascript vue.js javascript-marked

我正在为marked实现自定义渲染功能,该功能将检查图像上的一些条件,执行异步请求,然后从其他来源返回图像。但是,由于新请求是异步的,因此我只会得到一个诺言,而不是一个“真实的”图像网址。

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

我的渲染函数如下:

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调用中并返回(不包装在Promise.resolve中):

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

但是,这也只能给我一个诺言。

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

3 个答案:

答案 0 :(得分:1)

您可以推迟异步操作:

  1. 在您的自定义渲染器中,只需向img元素添加一些唯一的class名称,就应该区别对待。您还可以将src属性更改为某些加载图片。
  2. 然后,在呈现任何这些元素之前,创建一个MutationObserver并仅侦听添加的那些元素。然后,在MutationObserver的回调中,您可以执行异步操作并更新元素的src

答案 1 :(得分:0)

render函数本身必须是同步的

然后就不能在其中使用像ERROR: multiple drivers on net 'LED' (LED_SB_DFFNE_Q.Q and LED_SB_DFFNE_Q_1.Q) 这样的异步函数。您永远无法完成这项工作,这是完全不可能的。

相反,您将需要重新设计您的方法。评估条件并在调用getBlobUrl之前 进行异步请求。然后传递可以同步呈现的数据。

答案 2 :(得分: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
            })
    })
})

这是在vue js组件内发生的,该组件将this.preview转换为v-html到元素。

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

此解决方案类似于@shilch提出的解决方案,但我想应该是“ vue-y”。