Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 框架错误透传到引擎 #624

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/framework/src/infras/dock/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ function notifyAppError(id, param) {
info = param
}
// 同时触发新增的 onErrorHandler 生命周期
xHandleError(err, undefined, info, app)
xHandleError(err, undefined, info, app, undefined, true)
} catch (err) {
err.message = `$INTERRUPTION$:${err.message}`
throw err
Expand Down
56 changes: 48 additions & 8 deletions core/framework/src/shared/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ function getPageVmInCard(page) {
* @param info 附加错误信息
* @param app app 实例
* @param page page 实例
* @param isFromNative 错误是否来自客户端
*/
function xHandleError(err, vm, info = '', app, page) {
function xHandleError(err, vm, info = '', app, page, isFromNative = false) {
// 在处理错误处理程序时禁用 linker 跟踪,以避免可能的无限渲染
XLinker.pushTarget()
try {
Expand All @@ -51,15 +52,24 @@ function xHandleError(err, vm, info = '', app, page) {
try {
// 是否需要将错误向上传递
const capture = hooks[i].call(curVm, err, vm, info) === false
if (capture) return
if (capture) {
invokeJSError(err, info)
return
}
} catch (e) {
xGlobalHandleError(e, curVm, `page/component: lifecycle for "onErrorCaptured"`, app)
xGlobalHandleError(
e,
curVm,
`page/component: lifecycle for "onErrorCaptured"`,
app,
isFromNative
)
}
}
}
curVm = curVm._parent
}
xGlobalHandleError(err, vm, info, app)
xGlobalHandleError(err, vm, info, app, isFromNative)
} finally {
XLinker.popTarget()
}
Expand Down Expand Up @@ -97,8 +107,9 @@ function xInvokeWithErrorHandling(handler, context, args, vm, info, app, page) {
* @param vm vm
* @param info 附加错误信息
* @param app app 实例
* @param isFromNative 错误是否来自客户端
*/
function xGlobalHandleError(err, vm, info, app) {
function xGlobalHandleError(err, vm, info, app, isFromNative = false) {
let errorHandler
const _app = vm ? vm.$app : app

Expand All @@ -118,10 +129,14 @@ function xGlobalHandleError(err, vm, info, app) {
xLogError(e, undefined, `app: lifecycle for "onErrorHandler"`)
}
}
return
} else {
// 若 errorHandler 未定义,保证错误信息能正常输出
xLogError(err, vm, info)
}
// 来自客户端的错误不需要再去通知客户端
if (!isFromNative) {
invokeJSError(err, info)
}
// 若 errorHandler 未定义,保证错误信息能正常输出
xLogError(err, vm, info)
}

/**
Expand All @@ -147,6 +162,31 @@ function appError(app, err) {
}
}

/**
* 将框架捕获的错误传递给引擎上报
* @param err 捕获的错误
* @param info 附加错误信息
*/
function invokeJSError(err, info) {
const bridge = global.JsBridge
if (!bridge) {
console.trace(`### App Framework ### invokeJSError: JsBridge未初始化`)
} else {
if (typeof bridge.jsError === 'function') {
const params = {
message: `${err.name}: ${err.message}`,
stack: err.stack || '',
info: info
}
// 调用 jsError 方法,将错误信息传递给引擎
const res = bridge.jsError(params)
console.trace(`### App Framework ### invokeJSError: jsError 方法执行结果: ${res}`)
} else {
console.trace(`### App Framework ### invokeJSError: jsError 方法未初始化`)
}
}
}

/**
* 控制台输出错误信息
* @param err 错误
Expand Down
14 changes: 13 additions & 1 deletion core/framework/test/suite/bridge/platform/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, the hapjs-platform Project Contributors
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -178,6 +178,12 @@ function initMainPlatform(dslName) {
} else {
throw new Error(`ERROR: Unknown moduleName:${moduleName}, methodName:${methodName}`)
}
},
jsError(errObject) {
if (errObject.message && errObject.stack && errObject.info) {
return '{"code":0,"content":"success"}'
}
return '{"code":200,"content":"fail"}'
}
}
// 为canvas服务
Expand Down Expand Up @@ -257,6 +263,12 @@ function initWorkerPlatform(dslName = 'xvm') {
} else {
throw new Error(`ERROR: Unknown moduleName:${moduleName}, methodName:${methodName}`)
}
},
jsError(errObject) {
if (errObject.message && errObject.stack && errObject.info) {
return '{"code":0,"content":"success"}'
}
return '{"code":200,"content":"fail"}'
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,5 +487,27 @@ describe('框架: 01.框架错误捕获测试', () => {
// 还原 console.error
console.error = _oriConsoleError
app.isThrowError = false
resetErrorStatus()
})

it('捕获的错误传递给引擎上报', async () => {
const _oriConsoleTrace = console.trace

// 重写 console.trace
console.trace = function(str) {
// 因为许多地方都有用 console.trace 进行日志打印,所以需要通过条件进行筛选
if (str.includes('### App Framework ### invokeJSError')) {
expect(str).to.equal(
'### App Framework ### invokeJSError: jsError 方法执行结果: {"code":0,"content":"success"}'
)
}
}

pageVm.timeout()
await waitForOK()

// 还原 console.trace
console.trace = _oriConsoleTrace
resetErrorStatus()
})
})
Loading