Эта статья одновременно опубликована вмой блог
Автор ищет возможности.Если есть подходящая возможность внутреннего продвижения, пожалуйста, отправьте личное сообщение.Почтаили оставить сообщение
Недавно в своей работе я столкнулся с некоторымиQt
Разработка настольных гибридных приложений. Эта статья объединит часть моего собственного опыта разработки и расскажет о нем с точки зрения внешнего интерфейса.QWebChannel
существуетclient
Природа инстанцирования сторон и способыQWebChannel
Р ГVue.js
Похож на интерфейсный фреймворк.
Сначала вы должны быть в состоянии полностью понятьJS
модель цикла событийа такжеконтекст выполненияа такжестек контекста выполнения, позжеQWebChannel
Интеграция возьмет суть выполнения кода в качестве отправной точки для обсуждения реализации.QWebChannel
Интеграция с интерфейсными фреймворками. Хотя эта статьяVue.jsЭто пример, но он не ограничивает используемый вами интерфейсный фреймворк.Поняв принцип, читатели могут попробовать использоватьReactилиAngularПодождите, пока интерфейсная структура будет реализованаQWebChannel
интеграция.
Введение в технологию встроенных веб-страниц Qt
в текущемv5.xВ версии есть две реализации следующих гибридных приложенийDOC:
-
Qt WebViewЭтот модуль ужеv5.5в одеялеустарел, и являетсяQt WebEngineзаменятьDOC,API. Раньше он в основном использовался на мобильных терминалах и не включал полный
web
стек браузера при использовании родногоAPI
(то есть с использованием движка браузера на нативной стороне), реализованного вQMLСпособ отображения веб-страниц в приложении. Автор разрабатываетQt
При смешивании приложенийC++
Коллеги используютv5.6.2
(На момент написания этой статьи последней версией являетсяv5.13.1
), поэтому эта реализация гибридного приложения не обсуждается. -
Qt WebEngine, что само по себе обеспечивает
web
двигатель дляQt
Встраивайте произвольный веб-контент в приложение. Этоне зависеть отвнешнийWeb
Реализация гибридного применения двигателя также является наиболее простым способом. Стоит отметить, чтоQt WebEngine
основывается наChromiumПроект реализован, поэтому не содержит некоторыхGoogle
Также вGoogle Chrome
функции, реализованные наChromium
ПроэктИсходная библиотека восходящего потоканайти вChromiumа такжеGoogle Chrome
разница.
дляclient
серединаJS
По сути,Qt WebEngineв основном обеспечиваетJS
хост-среда (runtime
)—Chromiumпод проектv8двигатель. Также вQt
который предоставилweb
Механизм рендерингаChromiumв проектеblink.
Общение с JS в Qt v5+
в пониманииQt
После среды интеграции предусмотрен внешний интерфейс.Qt
представилQt WebChannel(именуемый в дальнейшемQWebChannel
) Концепция чего-либо. Это должно быть реализовано при условии, что выполнение кода на каждом конце не может быть затронуто.Qt
заканчиваться вclient
конец бесшовныйдвустороннийкоммуникация.
QWebChannelпредоставлено вServer
(C++
приложение) иclient
конец(HTML/JS
) возможность одноранговой связи. Черезclient
конецQWebChannelвыпускатьQObjectизпроизводный объект, который реализуется вclient
сторона, с которой можно легко читатьQt
конец公共插槽
а такжеQObjectиз属性值
а также方法
. В течение всего процесса связи нет необходимости в какой-либо ручной сериализации входящих параметров. всеQt
конец属性
обновить,signal
триггер, будетавтоматический и асинхронныйОбновить доclient
конец.
-
QObjectда
Qt
Ядро объектной модели в . Основная особенность этой модели называетсяsignalа такжеslotмеханизм связи объектов.
QWebChannel клиента
существуетQt
завершение реализацииQWebChannelПросто импортируйте соответствующийQt
модуль. реализоватьclient
конецQWebChannel, необходимо ввестиQt
официально предоставленqwebchannel.js
github,officialизJS
библиотека#. Цель этой библиотеки состоит в том, чтобы инкапсулировать рядКоммуникационный интерфейсИ метод сериализации информации при передаче информации.
для разных целейWeb
site существуют разные способы импорта статических файлов:
-
QWebEngineЛокализованные сайты в: Черезqrc:///qtwebchannel/qwebchannel.jsПредставлять.
-
Удаленно
web
сайт, официальныйqwebchannel.js
скопировать в цельweb
на сервере.
Перед реализацией связи необходимо создать экземплярQWebChannelобъект и передать объект для передаточной функции (называетсятранспортный объект) и функцию обратного вызова. однаждыQWebChannelзавершить создание экземпляра иРазместить объектЕсли доступно, будет вызвана функция обратного вызова, предоставленная в предыдущем экземпляре. Когда вызывается функция обратного вызова, канал устанавливается.
Пример кода выглядит следующим образом:
import QWebChannel from './qwebchannel.js'
/**
* @description window.qt.webChannelTransport 可用 WebSocket 实例代替。
* 经实践发现,Qt 向全局注入的 window.qt 仅有属性 webChannelTransport,并且该对象仅有
* 两个属性方法:send 和 onmessage
* send 方法用于 js 端向 Qt 端传输 `JSON` 信息
* onmessage 用于接受 `Qt` 端发送的 `JSON` 信息
*/
new QWebChannel(window.qt.webChannelTransport, initCallback)
в примере кодаwindow.qt.webChannelTransport
то естьtransport
объект иinitCallback
вQWebChannel
Завершите создание экземпляра и получитеQt
Функция обратного вызова, которая будет вызываться только после публикации объекта на стороне. Когда вызывается функция обратного вызова,Разместить объектдолжны быть доступны и содержать всеQt
общая информация на терминале, такая как属性
,方法
, за которым можно следитьcpp signal
и другая информация.
транспортный объект
Вообще под транспортом подразумеваются объекты window.qt.webChannelTransport (Qt сбоку через v8templatesв глобальную среду) или экземпляр WebSocket
указано вышеtransport
объект#Реализован минималистичный интерфейс передачи информации (interface
). Этовсегдадолжно бытьsendобъект метода,sendфункция (функциональное позиционирование этой функции может быть аналогичноWebSocket.send) будет передавать строковыйJSON
информацию и отправить ее наQt
конецQWebChannelAbstractTransportобъект. Кроме того, когдаtransport
Объект принимает завершение отQt
информация на стороне должна называтьсяtransport
объектonmessage
Атрибуты. По желанию вы можете использоватьWebSocket
для реализации интерфейса (т.е.transport
объект).
-
согласно сВторой абзац официального документаописывать,onmessageКогда функция вызывается, оназадача макросавызывается вместо того, чтобы вызываться после обертывания функцией источника микрозадачи (как
Promise.then
обернутая функция обратного вызова). -
#Note that all communication between the HTML client and the QML/C++ server is asynchronous. все в
client
а такжеQML/C++
Связь между сервисами естьасинхронныйиз.в официальномqwebchannel.jsвидимый в56 строка также65 строка также75 строк,когда
transport
объект получает отQt
информация на стороне, позвонюonmessageметод, поэтому этот метод по существу являетсяпарсер сообщений. Этим методом вJS
конецраспределениеразличные видыQt
сообщение, которое будет вызываться после инициализацииQWebChannel
Функция обратного вызова, определенная в callback. Это тожеQt
конец иJS
конецПрирода асинхронной связи. После отправки каждого сообщения функция отправки сообщения выходит из стека контекста выполнения и не блокирует текущую очередь задач, чтобы дождаться ответа на сообщение (task queue
).
Обратите внимание, что однаждыtransport
Когда объект доступен,JS
изQWebChannelОбъект должен быть создан. еслиWebSocket
реализации, а это означает, что вsocket
изonopen
должен быть создан в обратном вызовеQWebChannelобъект. в официальномQWebChannelнапример, на основеWebSocket
осуществленный. Позже будет описано, что нетWebSocket
Как добитьсяQt
конец иclient
Случайная асинхронная связь.
Обратный вызов создания экземпляра QWebChannel
однажды перешел кQWebChannelКогда вызывается функция обратного вызова конструктора, это указывает, чтоchannel
создание экземпляра завершено, и всеQt
опубликованоРазместить объектМожет пройтиchannel.objects
НедвижимостьJS
Клиентский доступ. Обратите внимание, что всеJS
клиент иQML/C++
Связь между сервисами естьасинхронныйиз. свойства могут бытьJS
Конец кэшируется. Кроме того, помните, что только можно преобразовать вJSON
изQML/C++
Тип данных будет должным образом сериализован или обратная последовательность, таким образом,JS
Клиентский доступ.
Здесь в анализе исходного кода позже можно сделать вывод, что:QWebChannel
Смысл создания экземпляра асинхронного обратного вызова заключается в реализации чего-то вродеTCPна этапе заключения договоратрехстороннее рукопожатие. для обеспеченияQt
конец иclient
Канал связи терминала обычно доступен.
interface Channel {
objects: {
[contextKey: string]: any
}
}
new QWebChannel(window.qt.webChannelTransport, (channel: Channel) => {
// 所有发布于 Qt 的发布对象都在 channel.objects 下
// 值得注意的是,必须提供一个上下文名称,将共享信息挂载到 channel.objects[上下文]
})
Стоит отметить, что вclient
передатьQt
При публикации объекта его необходимо совместить сclient
Вся информация, совместно используемая клиентом, монтируется на один или несколькоchannel.objects
Под пространством имен нельзя монтировать напрямую вchannel.objects
Вниз. который:
-
Qt
сторона: webchannel.cpp// WebBridge 类包含了一些与 JS 共享信息 class WebBridge: public QOject { Q_OBJECT public slots: void invokedByClient() { QMessageBox::information(NULL,"invokedByClient","I'm called by client JS!"); } }; WebBridge *webBridge = new WebBridge(); QWebChannel *channel = new QWebChannel(this); channel->registerObject('context', webBridge); view->page()->setWebChannel(channel);
-
client
сторона: мост/init.tsinterface Channel { objects: { context: { [contextKey: string]: any } [namespaceKey: any]: { [key: string]: any } } } new QWebChannel(window.qt.webChannelTransport, (channel: Channel) => { const qtContext = channel.objects.context // 此时 qtContext 包含了 Qt 端 context 命名空间下所有与 client 端共享的信息 })
Изучите сущность QWebChannel на стороне клиента
Согласно предыдущему заявлению,QWebChannelэкземпляр существуетФункция асинхронного обратного вызова. тогда дляИсследованиев каком видевозможностьприходи и уходиVue.js
Интеграция в другие фреймворкиQWebChannel
изопубликовать контейнер объектови избегайтеQWebChannel
контейнер опубликованных объектовchannel.objects
(включает всеpublished objects
- отQt
общая информация на стороне) напрямую выставлена в глобальной среде. будет обсуждаться нижеQWebChannel
изПуть инициализации (создание экземпляра + асинхронный обратный вызов)исследовать гору черезQWebChannel
Опубликовано изCpp
изРазместить объект.
существуетJS
боковая инициализацияQWebChannelКогда существует следующая логика для запускаQWebChannel
Экземпляр:
import QWebChannel from './qwebchannel.js'
new QWebChannel(window.qt.webChannelTransport, initCallback)
В приведенном выше коде в глобальной средеqt.webChannelTransport
Объект описан вышетранспортный объект. Объект создаетсяQt
конец черезC++
код, внедренный вclient
в глобальном окружении терминала. На практике обнаруживается, что объект находится вQt v5.6.2
При внедрении в версию включены только следующие два метода:
// TS types
interface MessageFromQt {
data: {
type: number
[dataKey: string]: any
}
}
declare global {
interface Window {
qt: {
webChannelTransport: {
send: (data: any) => void
onmessage: (message: MessageFromQt) => void
}
}
}
}
qt.webChannelTransport инъекция
распечатайте приведенный выше кодsend
метода видно, что тело функции не родноеJS
синтаксический код, ноv8 templates. В результате исследований было установлено, что вQtWebEngine
изоткрытый исходный код, показываятранспортный объектКак внедряется в глобальную среду. В целях сохранения преемственности темы статьи данная статья не корректна.C++
Код расширен и интерпретирован.Если читателям интересно, они могут комбинироватьQt
цитируется вChromium
И заголовочные файлыv8
изосновная концепциятак же кактип документаинтерпретировать.
Интерпретация в одном предложении: По существуQtWebEngine
с помощьюv8
Один экземпляр выборкиJS
глобальный объект, затем в глобальномglobal
Крепление на объектqt
объект и его подчиненныеwebChannelTransport
.
существуетздесьЧитатели могут найти официальную
Chromium
склад, и вGithubможно найти наChromium
зеркальный репозиторий. Кроме того, упомянутые выше заголовочные файлы в основном сосредоточены вgin
а такжеthird_party/blink
папка.
функция onmessage во время инициализации
в пониманииtransport
После введения вещества объекта,transport
второй метод в объектеonmessage
Функция может быть просмотренаqwebchannel.jsОбнаружение исходного кода, мы создаем экземплярQWebChannel
только что загруженSOURCE.
function QWebChannel(transport, initCallback) {
// some code is here
var channel = this
this.transport = transport // qt.webChannelTransport 或 一个 WebSocket 实例
// 注册 onmessage 函数以用于接受来自 `Qt` 端的 JSON 消息
this.transport.onmessage = function(message) {
var data = message.data
if (typeof data === 'string') {
data = JSON.parse(data)
}
switch (data.type) {
case QWebChannelMessageTypes.signal:
channel.handleSignal(data)
break
case QWebChannelMessageTypes.response:
channel.handleResponse(data)
break
case QWebChannelMessageTypes.propertyUpdate:
channel.handlePropertyUpdate(data)
break
default:
console.error('invalid message received:', message.data)
break
}
}
// some code is here
}
в каждом экземпляреQWebChannel
, глобальная среда будетqt.webChannelTransport
подняться наQWebChannelпримерtransport
в свойствахSOURCE. и экземплярsend
метод странспортный объектизsend
способ подключения. вызывающий экземплярsend
методПриродавыше, чтобы позвонитьтранспортный объектизsend
способQt
терминал для отправки сообщения. во время звонкатранспортный объектизsend
метод по существу вызывается передQt
внедряется в глобальную средуv8 template, чтобы добитьсяQt
отправлено изJS
Новости.
function QWebChannel(transport, initCallback) {
// some code is here
var channel = this
this.transport = transport
this.send = function(data) {
if (typeof data !== 'string') {
data = JSON.stringify(data)
}
// 即是调用 qt.webChannelTransport 或 WebSocket 实例的 send 方法
channel.transport.send(data)
}
// some code is here
}
трехстороннее рукопожатие
существуетqwebchannel.jsСледующие функции экземпляра существуют вexec
упаковатьтранспортный объектизsend
метод, какQt
способ отправки сообщенийодин. После отправки сообщения соответствующие функции обратного вызова сохраняются, и эти функции обратного вызова будут храниться в экземпляре экземпляра.execCallback
в свойствах.
this.execCallbacks = {} // 所有的回调函数容器
this.execId = 0
this.exec = // ... 后文将对此做必要分析
Если читатели заинтересованы, они могут углубиться в исходный код, чтобы узнать, отслеживает ли онC++
собственность по-прежнемуsignal
необходимо уведомить через эту функциюQt
конец.
// Qt signal 处理函数
this.handleSignal = //...
// Qt 消息处理函数,如通信初始化时的三次握手就是该函数来处理的。
this.handleResponse = // ...
// Qt 属性更新的处理函数
this.handlePropertyUpdate = // ...
Затем в зарегистрированном экземпляреexec
После метода 3 экземпляра впоследствии регистрируются для обработки изQt
Функция обратного вызова для сообщения.
QWebChannel
Завершающим этапом создания экземпляра является реализацияQt
канал связиинициализацияSOURCE, похожий наTCPпротокол三次握手
wiki. Целью этого шага является обеспечение доступности канала связи.
// 1. 调用前文所述的 exec 实例方法,通知 Qt 端初始化通信通道
// 2. 设定一个回调用于接受 Qt 端的初始化通道响应
channel.exec({ type: QWebChannelMessageTypes.init }, function(data) {
for (var objectName in data) {
// 创建信息载体 —— client 端的 QObject
var object = new QObject(objectName, data[objectName], channel)
}
// now unwrap properties, which might reference other registered objects
for (var objectName in channel.objects) {
channel.objects[objectName].unwrapProperties()
}
if (initCallback) {
// 调用初始化的回调函数
initCallback(channel)
}
// 3. 发送第三次握手信息
channel.exec({ type: QWebChannelMessageTypes.idle })
})
-
первое рукопожатие:существует
client
создалinit
сообщение и отправить наQt
терминал, для уведомленияQt
Конечная точка начинает инициализировать канал связи и возвращает объект публикации (если есть).-
существует
client
конецexecCallbacks
В контейнере, если есть функция обратного вызова ответа, сначала регистрируем функцию обратного вызова ответа, которая реализована следующим образом:this.exec = function(data, callback) { if (!callback) { // if no callback is given, send directly channel.send(data) return } if (channel.execId === Number.MAX_VALUE) { // wrap channel.execId = Number.MIN_VALUE } if (data.hasOwnProperty('id')) { console.error( 'Cannot exec message with property id: ' + JSON.stringify(data) ) return } data.id = channel.execId++ // 在 execCallbacks 容器中注册响应回调函数 channel.execCallbacks[data.id] = callback // 根据前文分析,本质调用的是 qt.webChannelTransport.send 方法 来向 Qt 通信 channel.send(data) }
-
отправить после
init
сообщение для инициализации канала связи дляQt
конец, осознатьпервое рукопожатие. Новостиbody
для:{ // QWebChannelMessageTypes 是源码顶部的配置对象 type: QWebChannelMessageTypes.init }
-
-
второе рукопожатие:
Qt
конец должен ответить на этоinit
сообщение, еслиclient
Терминал обычно может приниматьQt
Ответное сообщение от терминала выполнит описанную выше регистрацию в атрибуте экземпляра.execCallbacks
Соответствующая функция обратного вызова в контейнере.вызвать первымonmessageфункция (согласноПреамбула, все ответы даныonmessageобработки и диспетчеризации задач), которые затем будут обрабатываться соответствующими
channel.handleResponse
Функция обработчика для обработки ответа.this.handleResponse = function(message) { if (!message.hasOwnProperty('id')) { console.error( 'Invalid response message received: ', JSON.stringify(message) ) return } channel.execCallbacks[message.id](message.data) delete channel.execCallbacks[message.id] }
Здесь мы можем видеть, что раньше
init
перед отправкой сообщенияexecCallbacks
зарегистрирован в предыдущемinit
Обратный вызов для ответа на сообщение. в методе экземпляраhandleResponse
, удалит полезную нагрузку из ответа и передаст ее в обратный вызов ответа для завершениявторое рукопожатие. и после вызова обратного вызова ответа в контейнереexecCallbacks
удалить только что законченный вызов и выйтистек контекста выполненияфункция обратного вызова. -
третье рукопожатие: глубоковторое рукопожатиеОбратный вызов ответа, видимыйSOURCE:
function(data) { for (const objectName in data) { var object = new QObject(objectName, data[objectName], channel) } // now unwrap properties, which might reference other registered objects for (const objectName in channel.objects) { channel.objects[objectName].unwrapProperties() } if (initCallback) { // 调用 new QWebChannel 时传入的回调函数 initCallback(channel) } // 第三次握手发送 channel.exec({type: QWebChannelMessageTypes.idle}) }
Когда функция выполняется, она сначала принимает
Qt
Ответная информация терминала, создатьclient
конецQObject
для достиженияCpp
конецQObject
отслеживание. в инстанцированииQObject
, серииmethod
карта,signal
монитор,property
настройки монитора.в существовании
initCallback
при звонкеinitCallback
функция. Примечательно, что здесьinitCallback
создается экземпляр функцииQWebChannel
, передана вторая функция обратного вызова. позвони в это времяinitCallback
час,Qt
конецQObject
уже сclient
конец черезвторое рукопожатиедобиться синхронизации.наконец,
client
конецQt
конецтретье рукопожатиепросьба сообщитьQt
стороне, все опубликованные объекты уже находятся вclient
Окончание синхронизации завершено, и в это времяclient
Канал связи терминала входитidle
Период — ожидание сообщения, которое будет отправлено или отправлено.
Интеграция QWebChannel с Vue.js
Интегрируйте как плагин Vue.js
вот с помощьюVue.js
изМеханизм плагинареализовать паруQWebChannel
элегантная интеграция. выставить модуль наружуQWebChannel
экземпляр, а при создании экземпляраQWebChannelОбратный вызов инициализацииchannel.objects
зарегистрироваться наVue
прототип, что делает егоVue
изСвойства прототипа. Этот метод позволяет избежатьchannel.objects
Все опубликованоQt
Информационный объект на стороне просачивается в глобальную.
- _utils/index.ts
import Vue from 'vue'
export const isQtClient = (function() {
return navigator.userAgent.includes('QtWebEngine')
})()
export const bus = new Vue({})
export function assert(condition: any, msg: string) {
// falsy is not only 'false' value.
if (!condition)
throw new Error(msg || `[ASSERT]: ${condition} is a falsy value.`)
}
const __DEV__ = process.env.NODE_ENV !== 'development'
Приведенный выше код находится в_utils.js
Три служебные функции в .
function | описывать |
---|---|
isQtClient | используется для определения того, является лиQt изQWebEngine окружающая обстановка. Если среда разработки браузера будет имитироватьqt.webChannelTransport Объекты используются для предотвращения ошибок. |
bus | ОдинVue экземпляр, который будет использоваться вVue Реализовано на прототипеАсинхронное крепление. |
assert | Функция утверждения |
следующий вbridge/init.ts
установлен вQWebChannel
Процесс создания экземпляра:
- bridge/init.ts
import Vue from 'vue'
import QWebChannel from './qwebchannel' // 另有 qwebchannel.d.ts 声明文件
import { assert, isQtClient, bus, __DEV__ } from './_utils'
import dispatch from './index'
declare global {
interface Window {
qt: {
webChannelTransport: {
send: (payload: any) => void
onmessage: (payload: any) => void
}
}
}
}
export default {
install(Vue: Vue) {
if (!__DEV__) {
assert(
window && window.qt && window.qt.webChannelTransport,
"'qt' or 'qt.webChannelTransport' should be initialized(injected) by QtWebEngine"
)
}
// 用于在浏览器端开发时,模拟 `Qt` 的注入行为
if (__DEV__ && !isQtClient) {
window.qt = {
webChannelTransport: {
send() {
console.log(`
QWebChannel simulator activated !
`)
}
}
}
}
new QWebChannel(window.qt.webChannelTransport, function init(channel) {
const qtContext = channel.objects.context
// 官方示例直接在此,将整个 channel.objects 对象注册到全局对象上,这里并不推荐这样做。
/**
* @description 这里笔者采用的方法是注册到 Vue 的原型对象上,实现在任意子组件中都可访问 `Qt` 的所有发布在 context 下的发布对象。
*/
Vue.prototype.$_bridge = qtContext
/**
* @description 此处时调用了 Cpp 的同名方法 onPageLoaded
* @destination 用于通知 Qt 端 client 的 Vue.js 应用已经初始化完成
* @analysis 后文将会分析为什么此处回调可表示 Vue.js 应用已经完成初始化
*/
qtContext.onPageLoaded('', function(payload: string) {
dispatch(payload)
console.info(`
Bridge load !
`)
})
// 若有需求,可继续在此注册 C++ signal 的监听回调函数
// qtContext.onSignalFromCpp.connect(() => {})
// 以上注册了一个回调函数用于监听名为 onSignalFromCpp 的 signal
})
}
}
В приведенном выше примере кода главное, что нужно сделать, это:
- в текущем
Qt
В среде браузера создайте экземплярclient
конецQWebChannel
экземпляр используется сQt
конецасинхронныйкоммуникация. - существует
QWebChannel
в обратном вызове создания экземпляра будет исходить изQt
Все опубликованные объекты на стороне регистрируются наVue
экземпляр, так что любойVue
Доступ в компоненте экземпляраQt
опубликованный объект.
Анализ входного файла проекта Vue.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import '@/plugins/bridge' // 其中包含 bridge 异步挂载
Vue.config.productionTip = process.env.NODE_ENV === 'development'
new Vue({
router,
render: h => h(App)
}).$mount('#app')
В сочетании с анализом цикла событий
период, термин | имея в виду |
---|---|
модель цикла событий | HTML living standard |
задача макроса | HTML living standard, ECMA |
пройти черезVue
исходный код (или любойVue
Применяемый火焰图(flame chart)
) виден при начальном создании экземпляраVue
время (исключая обновление данных -Vue.js
обновление данныхасинхронныйобновлено), даСинхронизироватьсоздать экземпляр. затем объединитеJS 事件循环模型
только еслиsrc/main.ts
файл (скриншот1
) полностью выполняется и завершает работустек контекста выполнения, выполнит следующий宏任务
HTML living standard, ECMA. В настоящее время,onmessageТолько обратный вызов может стать следующей незавершенной записьюстек контекста выполненияиз宏任务
.
В общих чертах вышеизложенное основано наVue
Создание экземпляра (без обновления данных)Синхронизироватьиз宏任务
Эта сущность,QWebChannelсоздать экземпляр функции обратного вызоваinitCallback долженвVue
Выполняется после создания экземпляра. График пламени ниже10
хорошо видноVue
изСинхронизироватьпроцесс инициализации.
тогда потому что./src/main.ts
Сам входной файл представляет собоймодуль, тогда выполнение модуля,Webpack
обернуть это какфункция, то создается контекст выполнения. на основеExecution context 模型
ECMA, что эквивалентно./src/main.ts
Код в коде не выполняется полностью и выходитстек контекста выполнения, последующие宏任务(task)
всегда только в宏任务队列 (task queue)
вместо помещения в стек контекста выполнения. Вышеизложенное объясняет, почему инстанцированиеQWebChannelфункция обратного вызова, переданная вдолженвVue
инициализацияПозженазывается.
После объединения всего вышеперечисленного анализа нетрудно выйти:
-
initCallback
всегда вnew Vue
называется после.
- на основе
JS
измодель цикла событий,существуетinitCallback
когда звонили,router
Ждатьvue
В соответствии с описанной ранее функция должна быть доступна.
- комбинировать
1
, по крайней мере, не ранееVue
создание экземпляра завершено, иinitCallback
перед вызовом (т.трехстороннее рукопожатиедо того, как завершится второе рукопожатие), срабатываетsignal
ЖдатьQt
коммуникация.
FAQ
-
Почему бы не использовать в гибридных приложениях
URL
общаться?-
как можно ниже
C++
Связь между конечным и передним концами, позволяющая избежать ручной сериализации параметров и сращивания строк. При наличии вложенных объектов параметровJSON.stringify
Сложность значительно ниже, чем у рукописных функций сериализации. -
URL
длина ограничена, за пределамиURL
После ограничения длины последующие параметры будут отброшены. В то же время именно поэтому не должно бытьHTTP GET
Причина слишком большого количества параметров в запросе.
-