pdfjs 线程通信(二)
本来今天想了解一下绘制过程的,结果卡在了通信上,哈哈哈哈,继续来学习一下messge_handler,当时直接略过了,没想到这里面还有个槛。
pdfj是如何获取页面的绘制数据的?
一通debug以后,我们可以看到,主线程向pdf线程发了个GetOperatorList的消息,用的是messageHandler上的sendWithStream方法
const readableStream = this._transport.messageHandler.sendWithStream(
"GetOperatorList",
{
pageIndex: this._pageIndex,
intent: renderingIntent,
cacheKey,
annotationStorage: map,
modifiedIds,
},
transfer
);
const reader = readableStream.getReader();
这个方法返回了一个ReadableStream的实例,两句话有点难讲清楚,简单介绍一下把。
sendWithStream(actionName, data, queueingStrategy, transfers) {
const streamId = this.streamId++,
sourceName = this.sourceName,
targetName = this.targetName,
comObj = this.comObj;
return new ReadableStream(
{
start: controller => {
const startCapability = Promise.withResolvers();
this.streamControllers[streamId] = {
controller,
startCall: startCapability,
pullCall: null,
cancelCall: null,
isClosed: false,
};
……
pdfjs自己实现了线程之间流的通信协议,将页面的数据转换成操作命令通过流的方式(分chunk)传输给了主线程。
具体可以看message_handler.js和operator_list.js的实现, operator_list定义了flush方法,内部调用了sink的enqueue方法,将命令分批传输出去。
这样不仅解决了线程通信之间数据量过大的问题,而且主线程不需要等到全部的流传输完毕就可以开始绘制pdf页面了(线程之间互不影响),very nice。
ps: 页面数据和操作命令的转换过程可以看一下evaluator.js中的实现。
既然页面的绘制命令都拿到了,想要画出来就简单啦。
下期再介绍吧。