mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -05:00
Avoid calling destroy on the PDF.js loading task (#21277)
GitOrigin-RevId: b315e78ff739d301583f2139109f3244abceade8
This commit is contained in:
parent
aa0fe5aeb3
commit
5ec52e2e5b
3 changed files with 48 additions and 78 deletions
|
@ -1,7 +1,6 @@
|
||||||
import { FC, useCallback } from 'react'
|
import { FC, useCallback } from 'react'
|
||||||
import useIsMounted from '@/shared/hooks/use-is-mounted'
|
import useIsMounted from '@/shared/hooks/use-is-mounted'
|
||||||
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||||
import { debugConsole } from '@/utils/debugging'
|
|
||||||
|
|
||||||
const FileViewPdf: FC<{
|
const FileViewPdf: FC<{
|
||||||
fileId: string
|
fileId: string
|
||||||
|
@ -21,7 +20,6 @@ const FileViewPdf: FC<{
|
||||||
|
|
||||||
// bail out if loading PDF.js took too long
|
// bail out if loading PDF.js took too long
|
||||||
if (!mountedRef.current) {
|
if (!mountedRef.current) {
|
||||||
onError()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +35,6 @@ const FileViewPdf: FC<{
|
||||||
|
|
||||||
// bail out if loading the PDF took too long
|
// bail out if loading the PDF took too long
|
||||||
if (!mountedRef.current) {
|
if (!mountedRef.current) {
|
||||||
onError()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +44,12 @@ const FileViewPdf: FC<{
|
||||||
|
|
||||||
for (let i = 1; i <= pdf.numPages; i++) {
|
for (let i = 1; i <= pdf.numPages; i++) {
|
||||||
const page = await pdf.getPage(i)
|
const page = await pdf.getPage(i)
|
||||||
|
|
||||||
|
// bail out if the component has been unmounted
|
||||||
|
if (!mountedRef.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const viewport = page.getViewport({ scale })
|
const viewport = page.getViewport({ scale })
|
||||||
|
|
||||||
const canvas = document.createElement('canvas')
|
const canvas = document.createElement('canvas')
|
||||||
|
@ -64,11 +67,6 @@ const FileViewPdf: FC<{
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad()
|
onLoad()
|
||||||
|
|
||||||
return () => {
|
|
||||||
pdf.cleanup().catch(debugConsole.error)
|
|
||||||
pdf.destroy()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[mountedRef, pathInFolder, fileId, previewByPath, onLoad, onError]
|
[mountedRef, pathInFolder, fileId, previewByPath, onLoad, onError]
|
||||||
|
|
|
@ -64,24 +64,23 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||||
const handleContainer = useCallback(
|
const handleContainer = useCallback(
|
||||||
parent => {
|
parent => {
|
||||||
if (parent) {
|
if (parent) {
|
||||||
let wrapper: PDFJSWrapper | undefined
|
|
||||||
try {
|
try {
|
||||||
wrapper = new PDFJSWrapper(parent.firstChild)
|
setPdfJsWrapper(new PDFJSWrapper(parent.firstChild))
|
||||||
setPdfJsWrapper(wrapper)
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setLoadingError(true)
|
setLoadingError(true)
|
||||||
captureException(error)
|
captureException(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
|
||||||
setPdfJsWrapper(null)
|
|
||||||
wrapper?.destroy().catch(debugConsole.error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setLoadingError]
|
[setLoadingError]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
setPdfJsWrapper(null)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const [startFetch, setStartFetch] = useState(0)
|
const [startFetch, setStartFetch] = useState(0)
|
||||||
|
|
||||||
// listen for events and trigger rendering.
|
// listen for events and trigger rendering.
|
||||||
|
@ -181,7 +180,9 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||||
pdfJsWrapper
|
pdfJsWrapper
|
||||||
.loadDocument({ url, pdfFile, abortController, handleFetchError })
|
.loadDocument({ url, pdfFile, abortController, handleFetchError })
|
||||||
.then(doc => {
|
.then(doc => {
|
||||||
setTotalPages(doc.numPages)
|
if (doc) {
|
||||||
|
setTotalPages(doc.numPages)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (abortController.signal.aborted) return
|
if (abortController.signal.aborted) return
|
||||||
|
@ -190,7 +191,6 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
abortController.abort()
|
abortController.abort()
|
||||||
pdfJsWrapper.abortDocumentLoading()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [pdfJsWrapper, url, pdfFile, setError, setStartFetch])
|
}, [pdfJsWrapper, url, pdfFile, setError, setStartFetch])
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { captureException } from '@/infrastructure/error-reporter'
|
import { captureException } from '@/infrastructure/error-reporter'
|
||||||
import { generatePdfCachingTransportFactory } from './pdf-caching-transport'
|
import { generatePdfCachingTransportFactory } from './pdf-caching-transport'
|
||||||
import { debugConsole } from '@/utils/debugging'
|
|
||||||
import { PDFJS, loadPdfDocumentFromUrl, imageResourcesPath } from './pdf-js'
|
import { PDFJS, loadPdfDocumentFromUrl, imageResourcesPath } from './pdf-js'
|
||||||
import {
|
import {
|
||||||
PDFViewer,
|
PDFViewer,
|
||||||
|
@ -13,12 +12,11 @@ import 'pdfjs-dist/web/pdf_viewer.css'
|
||||||
const DEFAULT_RANGE_CHUNK_SIZE = 128 * 1024 // 128K chunks
|
const DEFAULT_RANGE_CHUNK_SIZE = 128 * 1024 // 128K chunks
|
||||||
|
|
||||||
export default class PDFJSWrapper {
|
export default class PDFJSWrapper {
|
||||||
private loadDocumentTask: PDFJS.PDFDocumentLoadingTask | undefined
|
|
||||||
|
|
||||||
public readonly viewer: PDFViewer
|
public readonly viewer: PDFViewer
|
||||||
public readonly eventBus: EventBus
|
public readonly eventBus: EventBus
|
||||||
private readonly linkService: PDFLinkService
|
private readonly linkService: PDFLinkService
|
||||||
private readonly pdfCachingTransportFactory: any
|
private readonly pdfCachingTransportFactory: any
|
||||||
|
private url?: string
|
||||||
|
|
||||||
// eslint-disable-next-line no-useless-constructor
|
// eslint-disable-next-line no-useless-constructor
|
||||||
constructor(public container: HTMLDivElement) {
|
constructor(public container: HTMLDivElement) {
|
||||||
|
@ -49,7 +47,7 @@ export default class PDFJSWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load a document from a URL
|
// load a document from a URL
|
||||||
loadDocument({
|
async loadDocument({
|
||||||
url,
|
url,
|
||||||
pdfFile,
|
pdfFile,
|
||||||
abortController,
|
abortController,
|
||||||
|
@ -60,61 +58,45 @@ export default class PDFJSWrapper {
|
||||||
abortController: AbortController
|
abortController: AbortController
|
||||||
handleFetchError: (error: Error) => void
|
handleFetchError: (error: Error) => void
|
||||||
}) {
|
}) {
|
||||||
// cancel any previous loading task
|
this.url = url
|
||||||
if (this.loadDocumentTask) {
|
|
||||||
this.loadDocumentTask.destroy().catch(debugConsole.error)
|
const rangeTransport = this.pdfCachingTransportFactory({
|
||||||
this.loadDocumentTask = undefined
|
url,
|
||||||
|
pdfFile,
|
||||||
|
abortController,
|
||||||
|
handleFetchError,
|
||||||
|
})
|
||||||
|
let rangeChunkSize = DEFAULT_RANGE_CHUNK_SIZE
|
||||||
|
if (rangeTransport && pdfFile.size < 2 * DEFAULT_RANGE_CHUNK_SIZE) {
|
||||||
|
// pdf.js disables the "bulk" download optimization when providing a
|
||||||
|
// custom range transport. Restore it by bumping the chunk size.
|
||||||
|
rangeChunkSize = pdfFile.size
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<PDFJS.PDFDocumentProxy>((resolve, reject) => {
|
try {
|
||||||
const rangeTransport = this.pdfCachingTransportFactory({
|
const doc = await loadPdfDocumentFromUrl(url, {
|
||||||
url,
|
|
||||||
pdfFile,
|
|
||||||
abortController,
|
|
||||||
handleFetchError,
|
|
||||||
})
|
|
||||||
let rangeChunkSize = DEFAULT_RANGE_CHUNK_SIZE
|
|
||||||
if (rangeTransport && pdfFile.size < 2 * DEFAULT_RANGE_CHUNK_SIZE) {
|
|
||||||
// pdf.js disables the "bulk" download optimization when providing a
|
|
||||||
// custom range transport. Restore it by bumping the chunk size.
|
|
||||||
rangeChunkSize = pdfFile.size
|
|
||||||
}
|
|
||||||
this.loadDocumentTask = loadPdfDocumentFromUrl(url, {
|
|
||||||
rangeChunkSize,
|
rangeChunkSize,
|
||||||
range: rangeTransport,
|
range: rangeTransport,
|
||||||
})
|
}).promise
|
||||||
|
|
||||||
this.loadDocumentTask.promise
|
// check that this is still the current URL
|
||||||
.then(doc => {
|
if (url !== this.url) {
|
||||||
if (!this.loadDocumentTask || !this.viewer) {
|
return
|
||||||
return // ignoring the response since loading task has been aborted
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const previousDoc = this.viewer.pdfDocument
|
this.viewer.setDocument(doc)
|
||||||
this.viewer.setDocument(doc)
|
this.linkService.setDocument(doc)
|
||||||
this.linkService.setDocument(doc)
|
|
||||||
resolve(doc)
|
|
||||||
|
|
||||||
if (previousDoc) {
|
return doc
|
||||||
previousDoc.cleanup().catch(debugConsole.error)
|
} catch (error: any) {
|
||||||
previousDoc.destroy().catch(debugConsole.error)
|
if (!error || error.name !== 'MissingPDFException') {
|
||||||
}
|
captureException(error, {
|
||||||
|
tags: { handler: 'pdf-preview' },
|
||||||
})
|
})
|
||||||
.catch(error => {
|
}
|
||||||
if (this.loadDocumentTask) {
|
|
||||||
if (!error || error.name !== 'MissingPDFException') {
|
|
||||||
captureException(error, {
|
|
||||||
tags: { handler: 'pdf-preview' },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
reject(error)
|
throw error
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loadDocumentTask = undefined
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the current scale value if the container size changes
|
// update the current scale value if the container size changes
|
||||||
|
@ -216,14 +198,4 @@ export default class PDFJSWrapper {
|
||||||
isVisible() {
|
isVisible() {
|
||||||
return this.viewer.container.offsetParent !== null
|
return this.viewer.container.offsetParent !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
abortDocumentLoading() {
|
|
||||||
this.loadDocumentTask = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
async destroy() {
|
|
||||||
await this.loadDocumentTask?.destroy().catch(debugConsole.error)
|
|
||||||
this.loadDocumentTask = undefined
|
|
||||||
await this.viewer.pdfDocument?.destroy().catch(debugConsole.error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue