Difference between revisions of "pas2js AsyncAWait"
Line 7: | Line 7: | ||
First of we have the async keyword, which you add as a procedure type modifier to turn it into an async function (or procedure). An async function knows how to expect the possibility of the await function being used to invoke asynchronous code. | First of we have the async keyword, which you add as a procedure type modifier to turn it into an async function (or procedure). An async function knows how to expect the possibility of the await function being used to invoke asynchronous code. | ||
− | + | Usually you call an async function via the await function. To explain the inner workings it is useful to see what happens when you call an async function directly. Then you get a TJSPromise: | |
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | uses JS; | ||
+ | |||
+ | function Run: word; async; | ||
+ | begin | ||
+ | Result:=3; | ||
+ | end; | ||
+ | |||
+ | var p: TJSPromise; | ||
+ | begin | ||
+ | p:=Run(); // calling directly without await() returns a TJSPromise! | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | |||
=AWait= | =AWait= |
Revision as of 21:17, 27 May 2020
Overview
Pas2js supports the JS operators async/await to simplify the use of Promise, which itself simplifies writing asynchronous code, like starting a download, waiting for the result, then depending on the result start the next and so forth. Instead of writing a tedious and hard to read mass of sub functions an async procedure can be written in the common serial aka imperative way.
Basics
First of we have the async keyword, which you add as a procedure type modifier to turn it into an async function (or procedure). An async function knows how to expect the possibility of the await function being used to invoke asynchronous code.
Usually you call an async function via the await function. To explain the inner workings it is useful to see what happens when you call an async function directly. Then you get a TJSPromise:
uses JS;
function Run: word; async;
begin
Result:=3;
end;
var p: TJSPromise;
begin
p:=Run(); // calling directly without await() returns a TJSPromise!
end.
AWait
Pas2js provides a built-in await function, which supports three flavours:
function await(AsyncFunctionOfResultTypeT): T;
function await(aType; p: TJSPromise): aType; // explicit promise requires the resolved type
function await(const Expr: T): T; // implicit promise
The await function can only be used inside a procedure with the async modifier.
An async procedure can contain multiple await calls.
Example Async try fetch
Example demonstrating waiting for an async function, catching errors with a try..except and no anonymous functions.
// Translated from https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
program askmom;
{$mode objfpc}
uses
browserconsole, JS, Web, SysUtils;
procedure myFetch; async;
var
response: TJSResponse;
myBlob: TJSBlob;
image: TJSHTMLImageElement;
objectURL: string;
begin
try
response := await(window.fetch('test1.png'));
if not response.ok then
raise Exception.Create('HTTP error! status: '+str(response.status))
else begin
myBlob := await(response.blob());
objectURL := URL.createObjectURL(myBlob);
image := TJSHTMLImageElement(document.createElement('img'));
image.src := objectURL;
document.body.appendChild(image);
end;
except
console.log(JSExceptValue);
end;
end;
begin
myFetch;
end.
Example Wait 2 Seconds
Program MyModule;
uses JS, Web;
function ResolveAfter2Seconds: TJSPromise;
// returns immediately with a Promise,
// which after 2 seconds gets resolved
begin
Result:=TJSPromise.new(procedure(resolve, reject : TJSPromiseResolver)
begin
window.setTimeout(procedure
begin
resolve('resolved');
end,
2000); // wait 2 seconds
end);
end;
procedure AsyncCall; async;
var s: string;
begin
writeln('calling');
s := await(string,resolveAfter2Seconds());
// the await pauses this procedure returning to the caller
// when the Promise from resolveAfter2Seconds gets resolved
// this procedure is continued
writeln(s); // expected output: 'resolved'
end;
begin
AsyncCall;
// calling AsyncCall returns immediately, while the Promise is waiting
writeln('called');
end.
Expected output:
calling called resolved