pdfjs源码学习(二)

pdfjs内部通信机制

这一块还是比较好理解的,因为发现自己曾经写过类似的代码> < ,当时为了解决桌面端和web页面之间的通信问题,自己手撸了一份简单的通信代码,和这个大差不差,人生就是在不停地重复造轮子。

不管怎么样,都来复习一遍吧。 一段经典的不能再经典的订阅发布代码

  1. message_handler
    核心js message_handler.js:用来处理线程之间的异步通信
  • construct 用来接收外部传入的消息处理对象,注册message 监听函数 #onMessage
  • actionHandler 用来存放注册的监听函数,key为监听函数的名称 actionName
  • on(actionName, handler) 函数用来注册消息
  • send(actionName, data, transfers) 发送消息
  • sendWithPromise(actionName, data, transfers) 这个对象里面唯一需要理解的就是这个函数啦,其实也不复杂,主要用来处理有回调值的函数。打个简单的比方,A 告诉 B ,你去烧壶水吧,然后B去做了 ,这个时候用send就行了。但是如果B烧完水需要告诉A结果,这个时候就需要用到sendWithPromise啦。这个场景是不是很熟悉 ?里面的关键就是 A 和 B 通过唯一的callbackId来当做彼此通信的标识,具体看源码就一目了然了。
  1. web worker
    解决性能的利器,可以创建多线程环境
    在这里插入图片描述
    pdf的文档下载就是交给web worker去处理的

  2. 主线程和pdf线程通过代理对象PDFDocumentProxy 进行交互

api.js 中的 WorkerTransport

   messageHandler.on("GetDoc", ({ pdfInfo }) => {
      this._numPages = pdfInfo.numPages;
      this._htmlForXfa = pdfInfo.htmlForXfa;
      delete pdfInfo.htmlForXfa;
      loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this)); 
    });

这段代码可以看到,pdf下载完以后返回的是一个代理对象,也就是外部操作document都是通过这个代理对象和真正的document进行交互

class PDFDocumentProxy {
 constructor(pdfInfo, transport) {
    this._pdfInfo = pdfInfo;
    this._transport = transport;
	……
  }
  ……
  getPage(pageNumber) {
    return this._transport.getPage(pageNumber);
  }
  ……
}

可以简单看一下PDFDocumentProxy 内部是如何获取页面的,transport就是构造代理对象的时候传入的messageHandler , getPage方法通过transport (messageHandler)发送了一个getPage的消息
api.js 中的 WorkerTransport

 getPage(pageNumber) {
 	……
    const promise = this.messageHandler
      .sendWithPromise("GetPage", {
        pageIndex,
      })
      .then(pageInfo => {
        if (this.destroyed) {
          throw new Error("Transport destroyed");
        }
        if (pageInfo.refStr) {
          this.#pageRefCache.set(pageInfo.refStr, pageNumber);
        }

        const page = new PDFPageProxy(
          pageIndex,
          pageInfo,
          this,
          this._params.pdfBug
        );
        this.#pageCache.set(pageIndex, page);
        return page;
      });
    this.#pagePromises.set(pageIndex, promise);
    return promise;
  }

线程接到GetPage的消息后调用pdfManager.getPage方法
worker.js 中的 WorkerMessageHandler

    handler.on("GetPage", function (data) {
      return pdfManager.getPage(data.pageIndex).then(function (page) {
        return Promise.all([
          pdfManager.ensure(page, "rotate"),
          pdfManager.ensure(page, "ref"),
          pdfManager.ensure(page, "userUnit"),
          pdfManager.ensure(page, "view"),
        ]).then(function ([rotate, ref, userUnit, view]) {
          return {
            rotate,
            ref,
            refStr: ref?.toString() ?? null,
            userUnit,
            view,
          };
        });
      });
    });


最后是pdfManger的getPage方法,通过真正的ducument获取page
pdf_manager.js 中的 BasePdfManager

  getPage(pageIndex) {
    return this.pdfDocument.getPage(pageIndex);
  }

好啦,一个简单的线程通信例子讲解完毕!
下次我们来看看pdfjs是如何渲染页面的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值