In Javascript running in a modern browser, I want to have a non-blocking call to a function.
I was pointed to Promises, and async functions that are built upon the top of them, but have discovered that Promises (and hence async functions) do block. See the code below that demonstrates this.
The only functions that do no block appear to be built in. E.g. setTimeout. This appears to be why all of the 'nonblocking' examples of Promises I've found use setTimeout. The single thread of execution walks through the time out code and calls the nonblocking setTimeout so keeps on stepping. The Promise itself is just organizing the callbacks, which is good, but they themselves are not causing calls to be non blocking.
The webworker solution doesn't appear to take a reference and thus can not modify the caller's data. Serializing, calling a web worker, then unserializing to get the result back would be rather inefficient, and complicated.
Here is a typical example of a getting 'non-blocking' behavior from a Promise, but if you single step through it in the web console, you will see the only thing that doesn't block is setTimeout.
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
'use strict';
function wait_setTimeout(call_when_finished){
console.log("entering wait_setTimeout");
setTimeout(call_when_finished, 2000); // 3 second delay
}
function wait_setTimeout_resolve(){
console.log("wait_setTimeout_resolved");
}
console.log("before wait_setTimeout promise");
let p0 = new Promise((wait_setTimeout_resolve) => {
this.wait_setTimeout(wait_setTimeout_resolve);
});
console.log("after new Promise(wait_setTimeout_resolve)");
p0.then(() => console.log("then wait_setTimeout_promise target"));
console.log("after wait_setTimeout_promise.then");
/*
before wait_setTimeout promise
entering wait_setTimeout
after new Promise(wait_setTimeout_resolve)
after wait_setTimeout_promise.then
<delay occurs here, as it should, but because setTimeout didn't block, not the Promise>
then wait_setTimeout_promise target
*/
</script>
</body>
If instead we create the time delay with a loop it is clear that the Promise is blocking:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
'use strict';
let limit = 100000; // ~3 second delay, make this bigger if you don't see a delay
function wait_loop(call_when_finished){
console.log("entering wait_loop");
let i = 0;
let j;
while(i < limit){
i++;
j = 0;
while(j < limit){
j++;
}}
call_when_finished();
}
function wait_loop_resolve(){
console.log("wait_loop_resolved");
}
console.log("before wait_loop promise");
let p1 = new Promise((wait_loop_resolve) => {
this.wait_loop(wait_loop_resolve);
});
console.log("after new Promise(wait_loop_resolve)");
p1.then(() => console.log("then wait_loop_promise target"));
console.log("after wait_loop_promise.then");
/*
before wait_loop promise
entering wait_loop
<delay occurs here.. i.e. the new Promise blocked>
after new Promise(wait_loop_resolve)
after wait_loop_promise.then
then wait_loop_promise target
*/
</script>
</body>
Of course the loop is just a placeholder. The actual code is computing something that is needed.