{ "id": "175064", "key": "TIMOB-27926", "fields": { "issuetype": { "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "name": "Improvement", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": null, "resolutiondate": null, "created": "2020-06-02T15:56:00.000+0000", "priority": { "name": "None", "id": "6" }, "labels": [], "versions": [], "issuelinks": [], "assignee": null, "updated": "2020-06-02T15:56:00.000+0000", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "components": [ { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "h5.Description\r\n\r\nWe currently expose the [uncaughtException|https://docs.appcelerator.com/platform/latest/#!/api/Titanium.App-event-uncaughtException] event on {{Titanium.App}} to handle errors that get thrown but not handled. However this does not include unhandled promise rejections or errors from within async functions\r\n\r\nAs we include core-js there is a default handler for unhandled error in promises that can also be overriden by a user like below, but this means that there is no integration with something like ACA, or the error dialog.\r\n\r\n{code}\r\nglobal.onunhandledrejection = e => console.log('unhandled', e.reason, e.promise);\r\n{code}\r\n\r\nFrom testing also, we are not consistent across platforms. On iOS an async function will be caught by {{onunhandledrejection}} as it is transpiled down to promises, but on android the error will be swallowed\r\n\r\nBelow is code that throws 3 types of errors\r\n\r\n{code: title= Test Code}\r\nconst win = Ti.UI.createWindow()\r\nconst lbl = Ti.UI.createLabel({ text: 'Callback error', top: 100 });\r\nlbl.addEventListener('click', () => {\r\n\tconsole.log('throwing from callback');\r\n\tthrow new Error('Callback error');\r\n});\r\nconst lbl2 = Ti.UI.createLabel({ text: 'Promise thrown', top: 250 });\r\nlbl2.addEventListener('click', () => {\r\n\tPromise.resolve()\r\n\t\t.then(() => {\r\n\t\t\tconsole.log('throwing from promise');\r\n\t\t\tthrow new Error('Promise thrown error')\r\n\t\t})\r\n});\r\nconst lbl3 = Ti.UI.createLabel({ text: 'Async thrown', top: 400 });\r\nlbl3.addEventListener('click', async () => {\r\n\tconsole.log('throwing from async');\r\n\tthrow new Error('Async function thrown error');\r\n});\r\nTi.App.addEventListener('uncaughtException', (e) => {\r\n\tconsole.log('uncaughtException handler');\r\n\tconsole.log(e);\r\n});\r\nwin.add(lbl);\r\nwin.add(lbl2);\r\nwin.add(lbl3);\r\nwin.open();\r\n{code}\r\n\r\n\r\nI'm unsure on the expected result here, it might make sense for us to ensure that errors from async functions/promises are handled via the uncaughtException event", "attachment": [], "flagged": false, "summary": "TiAPI: Expose a way to track unhandled promises", "creator": { "name": "eharris", "key": "eharris", "displayName": "Ewan Harris", "active": true, "timeZone": "Europe/Dublin" }, "subtasks": [], "reporter": { "name": "eharris", "key": "eharris", "displayName": "Ewan Harris", "active": true, "timeZone": "Europe/Dublin" }, "environment": null, "comment": { "comments": [], "maxResults": 0, "total": 0, "startAt": 0 } } }