The WebKit-based WKWebView documentation provides a callAsyncJavaScript() method with the following example:
var p = new Promise(function (f) {
window.setTimeout("f(42)", 1000);
});
await p;
return p;
Various attempts to run this example code pattern return the same "Completion handler for function call is no longer reachable" error:
Error Domain=WKErrorDomain Code=4
"A JavaScript exception occurred"
UserInfo={
WKJavaScriptExceptionLineNumber=0,
WKJavaScriptExceptionMessage="Completion handler for function call is no longer reachable",
WKJavaScriptExceptionColumnNumber=0,
NSLocalizedDescription="A JavaScript exception occurred"
}
I've tried several tweaks of the example code with callAsyncJavaScript
. The callAsyncJavaScript
call always returns with the same "... no longer reachable" error.
Here one variant which runs without error in the browser JS console, that does not work with callAsyncJavaScript
:
Why the error? Can the example somehow successfully run with WKWebView
callAsyncJavaScript
? If yes, then how?
Additional detail
The issue may be that the Promise
does not properly resolve in the documentation example.
The code below has added console.log()
tracing information.
let tracer = "a"
console.log("tracer:", tracer);
f = function (nProperty) {
let nResult = nProperty * 2
console.log("nResult:", nResult);
tracer = tracer + "d"
console.log("tracer:", tracer);
return nResult;
};
var p = new Promise(function (f) {
tracer = tracer + "b"
console.log("tracer:", tracer);
window.setTimeout("f(42)", 500);
});
console.log("BEFORE await:", p);
tracer = tracer + "c"
console.log("tracer:", tracer);
await p;
console.log("AFTER await:", p);
tracer = tracer + "e"
console.log("tracer:", tracer);
When above is run in the a Firefox JS console, the execution stops at the await statement. Here's the Firefox JS console output:
tracer: a
tracer: ab
BEFORE await: Promise { <state>: "pending" }
tracer: abc
nResult: 84
tracer: abcd
The statement console.log("AFTER await:", p);
is never executed.
And, one more detail...
From a Swift programmer point of view, one would expect that a successful JavaScript example which is called from the Swift callAsyncJavaScript(…) would expressly return a useful result from the JavaScript back to the Swift Result<Any, Error>)
.
Note that callAsyncJavaScript(…)
executes a provided String
of JavaScript as an asynchronous JavaScript function.
// do some JavaScript actions, await a result, and then..
return somthingUseful;