写在开篇
继《 Chrome Extension通信相关(汇总) 》后,笔者在编写了部分端的通信demo之后,觉得有必要在说具体的端到端的通信流程之前,先给大家讲一点理论的东西:什么是长链接?什么是短连接?以及,它们在Chrome Extension中又是什么地位?
消息通信
消息通信 是Chrome Extension的一个核心概念。因为Chrome Extension自身就包括了Content、Service Worker、option、popup等部分,而且每个部分运行的上下文不太一致,比如 Content 的执行上下文在插件的隔离环境中(与 Tab页 共享了 window与DOM的部分数据与函数 ),所以不仅为了一个插件内部的应用完整性,也为了插件更广的受众面,就需要设计“一个插件中的部分之间、插件与插件之间、插件与原生应用之间、插件与WEB端之间”的通信方案。
对于消息处理,Chrome Extension的设计方案是:发送方发送消息、接收方设置接收消息的监听函数,在监听函数中根据参数内容有序处理对应消息。
而,关于通信通道建立与使用,插件有两种方式:
- 一种是一次性消息通信通道,即 短连接,即时建立通信通道,发送完即销毁、关闭通信通道,一般用于:Chrome extension部分之间发送单条消息,并且,按需获取接收方的回复的场景下;
- 另一种是长连接,即,建立一个通信通道,在通道有效的时间段内,可以往复多次传递消息。当长链接通信通道建立时,每个端都会分配一个 runtime.Port 对象,以用于发送和接收消息;
短连接
对比长链接,短连接的优势在于:当发送方向接收方发送消息之后,可以同步等待接收方回复消息;
然而,从资源利用率上来说,每次都要建立通信通道,同等的发送消息数量下,相比长链接来说,这个执行效率和资源利用率肯定是低的,但又从现实的业务落地上来说,笔者还没有遇到过这种效率瓶颈,也就是一般的业务场景还没必要去考虑这个效率限制;
另外,针对短连接的消息回复,官方有这样一个提示:
If multiple pages are listening for onMessage events, only the first to call sendResponse() for a particular event will succeed in sending the response. All other responses to that event will be ignored.
关于这个提示,大致意思就是当短连接消息发送出去后,由于有多个监听函数在处理这条消息,而最终,发送方接收到的回复是多个监听函数中最先调用返回的那条消息,其他晚到的消息都会被忽略,这就是官方一直提醒的“消息回复竞争问题”,具体使用场景请参考笔者的另一篇文章《 Chrome Extension短连接消息回复竞争问题 》;
长连接
当在一个场景中,短时间内两个部分之间需要往复的发送好几个来回的消息的,一般使用长连接;
长连接中最重要的概念就是 runtime.Port 对象。当Chrome Extension两个部分之间建立起通信通道之后,两个部分都会被分配一个runtime.Port 对象,用于收发消息;其中,关于两个部分,我们区分成:发起创建方、接收方;
而,runtime.Port 对象最重要的一块内容就是生命周期,即,什么时候创建?什么时候不可用?
什么时候创建port对象?当 程序中调用chrome.runtime.connect() 或 chrome.tabs.connect()函数,且,有任意一个接收方创建了监听函数 时创建port对象。
那什么时候port对象不可用,即,通信通道被关闭呢?
- 当所有的接收方的监听函数都已经被销毁时,或,从一开始,根本就没有接收方设置任何监听函数时;
- 当 发起创建方 已经被卸载(比如TAB页被关闭或重定向、Service Worker进入休眠状态);
- 任何一方调用runtime.Port.disconnect() 函数时。
到此,为了保证通信可用性,你肯定有疑问:当通信通道关闭时,我们是否有方法知道呢?
当然是有的,就是我们在接收方或创建方的port上设置runtime.Port.onDisconnect监听函数后,当连接关闭时,相应的对方监听函数中就可以接收到断联的消息。
为什么是对方呢?经实践验证,如果是 发起创建方 主动调用了disconnect函数的,则对应的各个接收方会在port.onDisconnect的监听函数中在收到断联消息;当接收方主动调用disconnect函数的,则发起创建方会在onDisconnect的监听函数中在收到断联消息;
那监听这个通信通道关闭状态又有什么用呢?
- 第一要务当然是为顺利通信做准备,比如发现这个通信通道被关闭了,那就再次发起创建通信通道以备后续收发消息;
- 第二作用其实是“第一要务”的副作用,比如,当Service Worker进入休眠时会自动断开与Content层的长链接,而此时如果Content层监听发现了这个断联状态,那就让Content层重新向Service Worker请求建立时,Service Worker会被从休眠状态中唤起。这个副作用可以说是“促使Service Worker保持长期激活状态”的一种技术方案。
写在最后
到此,理论层面的长短连接通信方式就讲完了,希望你可以将一些重点内容记忆一下,以便更好的理解后续“各个端与端之间的通信方式”~