Merge pull request #776 from nofficalfs/Dev-Enhancement-Noname
fix some question.
This commit is contained in:
commit
07c3dbd6d4
201
game/game.js
201
game/game.js
|
@ -1,100 +1,101 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
// 客户端自带core.js的请注意跟进
|
// 客户端自带core.js的请注意跟进
|
||||||
if ('__core-js_shared__' in window) resolve(null);
|
if ('__core-js_shared__' in window) resolve(null);
|
||||||
else {
|
else {
|
||||||
const nonameInitialized = localStorage.getItem('noname_inited');
|
const nonameInitialized = localStorage.getItem('noname_inited');
|
||||||
const assetURL = typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized;
|
const assetURL = typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized;
|
||||||
const coreJSBundle = document.createElement('script');
|
const coreJSBundle = document.createElement('script');
|
||||||
coreJSBundle.onerror = coreJSBundle.onload = resolve;
|
coreJSBundle.onerror = coreJSBundle.onload = resolve;
|
||||||
coreJSBundle.src = `${assetURL}game/core-js-bundle.js`;
|
coreJSBundle.src = `${assetURL}game/core-js-bundle.js`;
|
||||||
document.head.appendChild(coreJSBundle);
|
document.head.appendChild(coreJSBundle);
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
const nonameInitialized = localStorage.getItem('noname_inited');
|
const nonameInitialized = localStorage.getItem('noname_inited');
|
||||||
const assetURL = typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized;
|
const assetURL = typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized;
|
||||||
const userAgent = navigator.userAgent.toLowerCase();
|
const userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
|
||||||
const exit = () => {
|
const exit = () => {
|
||||||
const ios = userAgent.includes('iphone') || userAgent.includes('ipad') || userAgent.includes('macintosh');
|
const ios = userAgent.includes('iphone') || userAgent.includes('ipad') || userAgent.includes('macintosh');
|
||||||
//electron
|
//electron
|
||||||
if (typeof window.process == 'object' && typeof window.require == 'function') {
|
if (typeof window.process == 'object' && typeof window.require == 'function') {
|
||||||
const versions = window.process.versions;
|
const versions = window.process.versions;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const electronVersion = parseFloat(versions.electron);
|
const electronVersion = parseFloat(versions.electron);
|
||||||
let remote;
|
let remote;
|
||||||
if (electronVersion >= 14) {
|
if (electronVersion >= 14) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
remote = require('@electron/remote');
|
remote = require('@electron/remote');
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
remote = require('electron').remote;
|
remote = require('electron').remote;
|
||||||
}
|
}
|
||||||
const thisWindow = remote.getCurrentWindow();
|
const thisWindow = remote.getCurrentWindow();
|
||||||
thisWindow.destroy();
|
thisWindow.destroy();
|
||||||
window.process.exit();
|
window.process.exit();
|
||||||
}
|
}
|
||||||
//android-cordova环境
|
//android-cordova环境
|
||||||
//ios-cordova环境或ios浏览器环境
|
//ios-cordova环境或ios浏览器环境
|
||||||
//非ios的网页版
|
//非ios的网页版
|
||||||
else if (!ios) {
|
else if (!ios) {
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!localStorage.getItem('gplv3_noname_alerted')) {
|
if (!localStorage.getItem('gplv3_noname_alerted')) {
|
||||||
if (confirm('①无名杀是一款基于GPLv3协议的开源软件!\n你可以在遵守GPLv3协议的基础上任意使用,修改并转发《无名杀》,以及所有基于《无名杀》开发的拓展。\n点击“确定”即代表您认可并接受GPLv3协议↓️\nhttps://www.gnu.org/licenses/gpl-3.0.html\n②无名杀官方发布地址仅有GitHub仓库!\n其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!')) {
|
if (confirm('①无名杀是一款基于GPLv3协议的开源软件!\n你可以在遵守GPLv3协议的基础上任意使用,修改并转发《无名杀》,以及所有基于《无名杀》开发的拓展。\n点击“确定”即代表您认可并接受GPLv3协议↓️\nhttps://www.gnu.org/licenses/gpl-3.0.html\n②无名杀官方发布地址仅有GitHub仓库!\n其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!')) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
localStorage.setItem('gplv3_noname_alerted', true);
|
localStorage.setItem('gplv3_noname_alerted', true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window['b' + 'ann' + 'e' + 'dE' + 'x' + 'ten' + 's' + 'i' + 'o' + 'ns'] = ['\u4fa0\u4e49', '\u5168\u6559\u7a0b'];
|
window['b' + 'ann' + 'e' + 'dE' + 'x' + 'ten' + 's' + 'i' + 'o' + 'ns'] = ['\u4fa0\u4e49', '\u5168\u6559\u7a0b'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {["firefox" | "chrome" | "safari" | "other", number]}
|
* @returns {["firefox" | "chrome" | "safari" | "other", number]}
|
||||||
*/
|
*/
|
||||||
function coreInfo() {
|
function coreInfo() {
|
||||||
const regex = /(firefox|chrome|safari)\/([\d.]+)/;
|
const regex = /(firefox|chrome|safari)\/([\d.]+)/;
|
||||||
let result;
|
let result;
|
||||||
if (!(result = userAgent.match(regex))) return ["other", NaN];
|
if (!(result = userAgent.match(regex))) return ["other", NaN];
|
||||||
if (result[1] !== "safari") return [result[1], parseInt(result[2])];
|
if (result[1] !== "safari") return [result[1], parseInt(result[2])];
|
||||||
result = userAgent.match(/version\/([\d.]+).*safari/);
|
result = userAgent.match(/version\/([\d.]+).*safari/);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return ["safari", parseInt(result[1])];
|
return ["safari", parseInt(result[1])];
|
||||||
}
|
}
|
||||||
const [core, version] = coreInfo();
|
const [core, version] = coreInfo();
|
||||||
const supportMap = {
|
const supportMap = {
|
||||||
"firefox": 60,
|
"firefox": 60,
|
||||||
"chrome": 61,
|
"chrome": 61,
|
||||||
// 因为coreInfo不考虑子版本,故就强行只能以11运行
|
// 因为coreInfo不考虑子版本,故就强行只能以11运行
|
||||||
"safari": 11
|
"safari": 11
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core in supportMap && supportMap[core] > version) {
|
if (core in supportMap && supportMap[core] > version) {
|
||||||
const tip = '检测到您的浏览器内核版本无法支持ES Module,请立即升级浏览器或手机webview内核!';
|
const tip = '检测到您的浏览器内核版本无法支持ES Module,请立即升级浏览器或手机webview内核!';
|
||||||
console.error(tip);
|
console.error(tip);
|
||||||
const redirect_tip = '您使用的浏览器或无名杀客户端内核版本过低,已经无法正常运行无名杀!\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。\n稍后您的无名杀将自动退出(可能的话)';
|
const redirect_tip = '您使用的浏览器或无名杀客户端内核版本过低,已经无法正常运行无名杀!\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。\n稍后您的无名杀将自动退出(可能的话)';
|
||||||
if (confirm(redirect_tip)) {
|
if (confirm(redirect_tip)) {
|
||||||
window.open('https://github.com/libccy/noname/releases/tag/chromium77-client');
|
window.open('https://github.com/libccy/noname/releases/tag/chromium77-client');
|
||||||
}
|
}
|
||||||
exit()
|
exit()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const script = document.createElement('script')
|
const script = document.createElement('script')
|
||||||
script.type = "module";
|
script.type = "module";
|
||||||
script.src = `${assetURL}game/entry.js`
|
script.src = `${assetURL}game/entry.js`
|
||||||
script.async = true
|
script.async = true
|
||||||
script.onerror = (event) => {
|
script.onerror = (event) => {
|
||||||
console.error(event)
|
console.error(event)
|
||||||
const message = `您使用的浏览器或无名杀客户端加载内容失败!\n报错内容: \n${event}\n若该BUG不为您个人原因造成的,请及时反馈给无名杀开发组!`;
|
const message = `您使用的浏览器或无名杀客户端加载内容失败!\n请检查游戏环境以及"(游戏根目录)/game/entry.js"文件的位置\n若该BUG不为您个人原因造成的,请及时反馈给无名杀开发组!`;
|
||||||
alert(message);
|
console.error(message);
|
||||||
exit()
|
alert(message);
|
||||||
}
|
exit()
|
||||||
document.head.appendChild(script)
|
}
|
||||||
}
|
document.head.appendChild(script)
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
9109
noname/get/index.js
9109
noname/get/index.js
File diff suppressed because it is too large
Load Diff
|
@ -1,41 +1,41 @@
|
||||||
import { Game as game } from '../game/index.js';
|
import { Game as game } from '../game/index.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 卡牌包名
|
* @param {string} name - 卡牌包名
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importCardPack = generateImportFunction('card', (name) => `../../card/${name}.js`)
|
export const importCardPack = generateImportFunction('card', (name) => `../../card/${name}.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 武将包名
|
* @param {string} name - 武将包名
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importCharacterPack = generateImportFunction('character', (name) => `../../character/${name}.js`)
|
export const importCharacterPack = generateImportFunction('character', (name) => `../../character/${name}.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 扩展名
|
* @param {string} name - 扩展名
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importExtension = generateImportFunction('extension', (name) => `../../extension/${name}/extension.js`)
|
export const importExtension = generateImportFunction('extension', (name) => `../../extension/${name}/extension.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name - 模式名
|
* @param {string} name - 模式名
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export const importMode = generateImportFunction('mode', (name) => `../../mode/${name}.js`)
|
export const importMode = generateImportFunction('mode', (name) => `../../mode/${name}.js`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成导入
|
* 生成导入
|
||||||
*
|
*
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {(name: string) => string} pathParser
|
* @param {(name: string) => string} pathParser
|
||||||
* @returns {(name: string) => Promise<void>}
|
* @returns {(name: string) => Promise<void>}
|
||||||
*/
|
*/
|
||||||
function generateImportFunction(type, pathParser) {
|
function generateImportFunction(type, pathParser) {
|
||||||
return async (name) => {
|
return async (name) => {
|
||||||
const modeContent = await import(pathParser(name));
|
const modeContent = await import(pathParser(name));
|
||||||
if (!modeContent.type) return;
|
if (!modeContent.type) return;
|
||||||
if (modeContent.type !== type) throw new Error(`Loaded Content doesn't conform to "${type}" but "${modeContent.type}".`);
|
if (modeContent.type !== type) throw new Error(`Loaded Content doesn't conform to "${type}" but "${modeContent.type}".`);
|
||||||
await game.import(type, modeContent.default);
|
await game.import(type, modeContent.default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1951
noname/init/index.js
1951
noname/init/index.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,8 @@
|
||||||
import { Uninstantable } from "../../util/index.js";
|
import { Uninstantable } from "../../util/index.js";
|
||||||
|
|
||||||
export class Experimental extends Uninstantable {
|
import { ExperimentalSymbol } from "./symbol.js";
|
||||||
|
|
||||||
}
|
export class Experimental extends Uninstantable {
|
||||||
|
static symbol = ExperimentalSymbol
|
||||||
|
static symbols = ExperimentalSymbol
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Uninstantable } from "../../util/index.js";
|
||||||
|
|
||||||
|
export class ExperimentalSymbol extends Uninstantable {
|
||||||
|
static itemType = Symbol('noname.experimental.itemType')
|
||||||
|
}
|
29310
noname/ui/index.js
29310
noname/ui/index.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
||||||
|
import { PromiseErrorHandler } from './struct/index.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从浏览器名到不同浏览器下异步处理方式的映射
|
||||||
|
*
|
||||||
|
* `key`的值同`get.coreInfo`函数返回值的第一个元素
|
||||||
|
*
|
||||||
|
* @type {Record<"firefox" | "chrome" | "safari" | "other", new () => PromiseErrorHandler>}
|
||||||
|
*/
|
||||||
|
export const promiseErrorHandlerMap = {
|
||||||
|
'chrome': PromiseErrorHandler.ChromePromiseErrorHandler,
|
||||||
|
'firefox': PromiseErrorHandler.FirefoxPromiseErrorHandler,
|
||||||
|
'safari': PromiseErrorHandler.UnknownPromiseErrorHandler,
|
||||||
|
'other': PromiseErrorHandler.UnknownPromiseErrorHandler
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./struct/interface/promise-error-handler.js').PromiseErrorHandler} PromiseErrorHandler
|
||||||
|
*/
|
|
@ -1,18 +1,24 @@
|
||||||
/**
|
/**
|
||||||
*
|
* 一个非常普通的“锁”
|
||||||
*/
|
*/
|
||||||
export class Mutex {
|
export class Mutex {
|
||||||
/**
|
/**
|
||||||
|
* 锁目前的状态,只有“unlocked”和“locked”两种情况
|
||||||
|
*
|
||||||
* @type {'locked' | 'unlocked'}
|
* @type {'locked' | 'unlocked'}
|
||||||
*/
|
*/
|
||||||
#status;
|
#status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 上锁后用于等待的锁Promise
|
||||||
|
*
|
||||||
* @type {null | Promise<void>}
|
* @type {null | Promise<void>}
|
||||||
*/
|
*/
|
||||||
#promise;
|
#promise;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 上锁后用于触发锁Promise的resolve函数
|
||||||
|
*
|
||||||
* @type {null | function(): void}
|
* @type {null | function(): void}
|
||||||
*/
|
*/
|
||||||
#resolve;
|
#resolve;
|
||||||
|
@ -23,6 +29,11 @@ export class Mutex {
|
||||||
this.#resolve = null;
|
this.#resolve = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上锁
|
||||||
|
*
|
||||||
|
* 请时刻记住使用`await Mutex#lock()`来使锁正常工作
|
||||||
|
*/
|
||||||
async lock() {
|
async lock() {
|
||||||
switch (this.#status) {
|
switch (this.#status) {
|
||||||
case 'locked':
|
case 'locked':
|
||||||
|
@ -36,6 +47,11 @@ export class Mutex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解锁
|
||||||
|
*
|
||||||
|
* 请不要在未上锁的情况下解锁
|
||||||
|
*/
|
||||||
unlock() {
|
unlock() {
|
||||||
if (this.#status === 'unlocked') throw new Error('This Mutex is not locked.');
|
if (this.#status === 'unlocked') throw new Error('This Mutex is not locked.');
|
||||||
|
|
||||||
|
@ -44,6 +60,7 @@ export class Mutex {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 启用锁的try-finally封装,用于在函数执行完后自动解放锁的控制权(就算发生错误)
|
||||||
*
|
*
|
||||||
* @param {function(): void | Promise<void>} content
|
* @param {function(): void | Promise<void>} content
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
* 无名杀内部所需要的数据结构
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * as PromiseErrorHandler from './promise-error-handler/index.js';
|
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
* 无名杀内部构建所需要用到的接口
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { PromiseErrorHandler } from './promise-error-handler'
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* 不同浏览器下异步报错问题处理方式的接口,用于定义不同浏览器对待异步报错的处理方式
|
||||||
|
*/
|
||||||
|
export interface PromiseErrorHandler {
|
||||||
|
/**
|
||||||
|
* 当异步处理对象初始化时执行的操作
|
||||||
|
*
|
||||||
|
* 因为未来或许会涉及到错误处理方式的更改,故所有初始化操作请于此处执行
|
||||||
|
*
|
||||||
|
* 若该函数为异步函数,则将阻塞运行
|
||||||
|
*/
|
||||||
|
onLoad?(): void | Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当异步处理对象被释放时执行的操作
|
||||||
|
*
|
||||||
|
* 目前版本无任何用处,请等待未来的更新
|
||||||
|
*
|
||||||
|
* 未来或许会涉及到错误处理方式的更改,此后请使用无名杀提供的方式来进行异步错误处理的更改
|
||||||
|
*
|
||||||
|
* 若该函数为异步函数,则将阻塞运行
|
||||||
|
*/
|
||||||
|
onUnload?(): void | Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当全局监听器捕获到`unhandledrejection`事件时会调用的函数
|
||||||
|
*
|
||||||
|
* 该函数用于正式处理异步报错事件
|
||||||
|
*
|
||||||
|
* 该函数为异步函数时不会阻塞运行
|
||||||
|
*
|
||||||
|
* @param event - 被捕获到的异步报错事件
|
||||||
|
*/
|
||||||
|
onHandle?(event: PromiseRejectionEvent): void | Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当触发`window.onerror`时会调用的函数
|
||||||
|
*
|
||||||
|
* 用于在执行`window.onerror`前执行一些可能存在的善后操作
|
||||||
|
*
|
||||||
|
* 该函数无法为异步函数
|
||||||
|
*/
|
||||||
|
onErrorPrepare?(): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当`window.onerror`运行**即将结束**时会调用的函数
|
||||||
|
*
|
||||||
|
* 用于在执行`window.onerror`后执行一些可能存在的善后操作
|
||||||
|
*
|
||||||
|
* 该函数无法为异步函数
|
||||||
|
*/
|
||||||
|
onErrorFinish?(): void
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* 关于`Google Chrome`的异步错误处理
|
||||||
|
*
|
||||||
|
* `Chrome`所用的`v8`引擎为`Error`提供了特有的报错栈堆处理函数,用于用户自定义报错栈堆的内容。
|
||||||
|
*
|
||||||
|
* 我们用到了`Error.prepareStackTrace(error, structuredStackTrace)`这个函数,这个函数的信息可参考[这里](https://v8.dev/docs/stack-trace-api#customizing-stack-traces)
|
||||||
|
*
|
||||||
|
* 该函数提供了结构化的栈堆信息,很幸运的是,这个结构化的栈堆能直接告诉我们报错的文件以及位置,故我们使用该函数,让异步报错能直接定位原始位置
|
||||||
|
*
|
||||||
|
* @implements {PromiseErrorHandler}
|
||||||
|
*/
|
||||||
|
export class ChromePromiseErrorHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于临时记录报错信息的列表,通过`Error.prepareStackTrace`更新该列表
|
||||||
|
*
|
||||||
|
* @type {[Error, NodeJS.CallSite[]][]}
|
||||||
|
*/
|
||||||
|
#errorList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {typeof Error.prepareStackTrace}
|
||||||
|
*/
|
||||||
|
#originErrorPrepareStackTrace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化`Error.prepareStackTrace`,将该值赋值成我们需要的函数
|
||||||
|
*
|
||||||
|
* 未防止本来Error.prepareStackTrace便存在赋值的行为,我们将原始值存储,并在需要的函数中调用
|
||||||
|
*
|
||||||
|
* > 这或许就是本体扩展化的第一步(小声)
|
||||||
|
*/
|
||||||
|
onLoad() {
|
||||||
|
this.#errorList = [];
|
||||||
|
this.#originErrorPrepareStackTrace = Error.prepareStackTrace;
|
||||||
|
Error.prepareStackTrace = (error, stackTraces) => {
|
||||||
|
// 其实这步或许不需要
|
||||||
|
// 但真赋值了Error.prepareStackTrace的话,保不齐会出现需要返回值的情况
|
||||||
|
const result = this.#originErrorPrepareStackTrace
|
||||||
|
? this.#originErrorPrepareStackTrace(error, stackTraces)
|
||||||
|
: void 0;
|
||||||
|
this.#errorList.push([error, stackTraces]);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将原来可能的`Error.prepareStackTrace`赋值回去
|
||||||
|
*/
|
||||||
|
onUnload() {
|
||||||
|
Error.prepareStackTrace = this.#originErrorPrepareStackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在获取报错的时候,我们通过发生报错的`Promise`来进行捕获错误的操作
|
||||||
|
*
|
||||||
|
* 如果捕获出来的错误存放我们存报错栈堆的列表中,则证明该错误能获取到栈堆,由此来获取报错的地址和行列号
|
||||||
|
*
|
||||||
|
* @param {PromiseRejectionEvent} event
|
||||||
|
*/
|
||||||
|
onHandle(event) {
|
||||||
|
event.promise.catch((error) => {
|
||||||
|
const result = this.#errorList.find(savedError => savedError[0] === error);
|
||||||
|
if (result) {
|
||||||
|
// @ts-ignore
|
||||||
|
window.onerror(
|
||||||
|
result[0].message,
|
||||||
|
result[1][0].getScriptNameOrSourceURL(),
|
||||||
|
result[1][0].getLineNumber() || void 0,
|
||||||
|
result[1][0].getColumnNumber() || void 0,
|
||||||
|
result[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正式报错时便不再需要报错信息了,故直接清空列表,释放内存
|
||||||
|
*/
|
||||||
|
onErrorPrepare() {
|
||||||
|
this.#errorList.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../interface/promise-error-handler').PromiseErrorHandler} PromiseErrorHandler
|
||||||
|
*/
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* 关于`Mozilla Firefox`的异步错误处理
|
||||||
|
*
|
||||||
|
* 很幸运,Mozilla直接为`Firefox`的报错提供了地址和行列号,故我们能直接获取到要获取的信息,不用像`v8`那样通过栈堆获取
|
||||||
|
*
|
||||||
|
* 虽然但是,我们还是需要判断一下捕获的报错是否是错误
|
||||||
|
*
|
||||||
|
* @implements {PromiseErrorHandler}
|
||||||
|
*/
|
||||||
|
export class FirefoxPromiseErrorHandler {
|
||||||
|
/**
|
||||||
|
* 在获取报错的时候,我们通过发生报错的`Promise`来进行捕获错误的操作
|
||||||
|
*
|
||||||
|
* 如果捕获到的错误是`Error`,则能直接通过`Firefox`的特性来获取地址和行列号
|
||||||
|
*
|
||||||
|
* @param {PromiseRejectionEvent} event
|
||||||
|
*/
|
||||||
|
onHandle(event) {
|
||||||
|
event.promise.catch((error) => {
|
||||||
|
if (typeof error === 'object' && error instanceof Error) {
|
||||||
|
// Firefox在大环境下默认情况必须要那么多ts-ignore
|
||||||
|
// @ts-ignore
|
||||||
|
window.onerror(
|
||||||
|
error.message,
|
||||||
|
// @ts-ignore
|
||||||
|
error.fileName,
|
||||||
|
// @ts-ignore
|
||||||
|
error.lineNumber,
|
||||||
|
// @ts-ignore
|
||||||
|
error.columnNumber,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../interface/promise-error-handler').PromiseErrorHandler} PromiseErrorHandler
|
||||||
|
*/
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* 关于不同浏览器下对异步错误的处理方式
|
||||||
|
*
|
||||||
|
* 目前已实现的浏览器如下:
|
||||||
|
*
|
||||||
|
* - `Google Chrome`(包括`electron`、`cordova`以及`crosswalk`)
|
||||||
|
* - `Mozilla Firefox`
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { ChromePromiseErrorHandler } from './chrome.js';
|
||||||
|
export { FirefoxPromiseErrorHandler } from './firefox.js';
|
||||||
|
export { UnknownPromiseErrorHandler } from './unknown.js';
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* 关于除已实现浏览器外其余浏览器的异步错误处理
|
||||||
|
*
|
||||||
|
* 很遗憾,对于这类浏览器,因为标准未涉及报错栈堆或地址及行列号,故我们只能直接,暴力的throw出我们捕获道德错误,
|
||||||
|
*
|
||||||
|
* 尽管我们还是会为了这类浏览器判断是不是捕获到了一个`Error`
|
||||||
|
*
|
||||||
|
* 总之,虽然这里跟Safari无关,但我们还是为新时代IE默哀一秒
|
||||||
|
*
|
||||||
|
* @implements {PromiseErrorHandler}
|
||||||
|
*/
|
||||||
|
export class UnknownPromiseErrorHandler {
|
||||||
|
/**
|
||||||
|
* 在获取报错的时候,我们通过发生报错的`Promise`来进行捕获错误的操作
|
||||||
|
*
|
||||||
|
* 如果捕获到的错误是`Error`,则...我们只能暴力的将`Error`再次`throw`出去
|
||||||
|
*
|
||||||
|
* @param {PromiseRejectionEvent} event
|
||||||
|
*/
|
||||||
|
onHandle(event) {
|
||||||
|
event.promise.catch((error) => {
|
||||||
|
if (typeof error === 'object' && error instanceof Error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../interface/promise-error-handler').PromiseErrorHandler} PromiseErrorHandler
|
||||||
|
*/
|
Loading…
Reference in New Issue