BlogAll Blog Posts | Next Post | Previous Post
Monday, April 05, 2021
Even these Delphi developers who have only set the very first steps into web client development will realize that quite a few important functionalities in web clients are executed only asynchronously by the browser.
First of all, why did the creators of browser implement certain functionality only asynchronously? The answer to this question is quite simple. For the developers behind the browser, the user experience comes first and a UI that freezes is a big no-go. At all times, the user interface should remain response. The user should never get the impression that the browser or the machine hangs while navigating on the internet. Now, several operations happening in the browser client application can by nature have a fairly unpredictable time to execute. So, no such function should stop the execution of user interface handling code in the browser.
Example 1: handling via an event:
// method starting the HTTP request procedure TForm1.WebButton1Click(Sender: TObject); begin WebHttpRequest1.URL := 'https://www.tmssoftware.com/sample.json'; WebHttpRequest1.Execute(); end; // TWebHTTPRequest event handler for OnResponse procedure TForm1.WebHttpRequest1Response(Sender: TObject; AResponse: string); var jo: TJSONObject; jv: TJSONValue; begin jo := TJSONObject.Create; try jv := jo.ParseJSONValue(AResponse) // do any further processing here on the parsed JSON finally end; end;
Example 2: handling via an anonymous method:
procedure TForm1.WebButton1Click(Sender: TObject); begin WebHttpRequest1.URL := 'https://www.tmssoftware.com/sample.json';
WebHttpRequest1.Execute( procedure(AResponse: string; ARequest: TJSXMLHttpRequest) var jo: TJSOBject; jv: TJSONObject; begin jv := TJSONObject.Create; try jv.ParseJSONValue(AResponse); // do any further processing here on the parsed JSON finally end; end); end;
Now, while the implementation using anonymous methods probably leads to fairly readable code, imagine needing to handle with multiple HTTP requests that depend on each other, which is in web development a fairly common use-case. While you can in theory invoke another http request from the anonymous method handler that is in turn also handled by a new anonymous method handler, you can see that it quickly becomes clumsy.
Now, in TMS WEB Core v1.7, we have already introduced in many components functions returning promises where you can use at application level, await() constructs to handle the code 'sequentially'. An example of this is the TWebHttpRequest.Perform: TJSPromise function that now allows to perform HTTP requests and deal with these with an await. The equivalent code for the first two examples becomes:
procedure TForm1.WebButton1Click(Sender: TObject); var req: TJSXMLHttpRequest; jo: TJSONOBject; begin WebHttpRequest1.URL := 'https://www.tmssoftware.com/sample.json'; try req := await(TJSXMLHttpRequest, WebHttpRequest1.Perform()); jo := TJSONObject.Create; jv := jo.ParseJSONValue(string(req.response));
except // handle failure to execute request here end; end;
type TForm1 = class(TWebForm) [async] procedure WebButton1Click(Sender: TObject); end;
TMS WEB Core v1.7 includes many new TJSPromise functions
var newform: TForm2; begin newform := TForm2.CreateNew(procedure(AForm: TObject) begin // anonymous method needed as the form is asynchronously loaded and initialized (AForm as TForm2).frm2Edit.Text := WebEdit1.Text; end ); newform.Caption := 'Child form'; // asynchronously handling closing the form via an anonymous method newform.ShowModal(procedure(AValue: TModalResult) begin ShowMessage('Form 2 closed with new value:"'+newform.frm2Edit.Text+'"'); WebEdit1.Text := newform.frm2Edit.Text; newform.Free; end ); end;
procedure TForm1.WebButton1Click(Sender: TObject); var newform: TForm2; mr: TModalResult; begin newform := TForm2.Create(Self); newform.Caption := 'Child form'; // load file HTML template + controls await(TForm2, newform.Load()); // init control after loading newform.frm2Edit.Text := WebEdit1.Text; try // excute form and wait for close mr := await(TModalResult, newform.Execute); ShowMessage('Form 2 closed with new value:"'+newform.frm2Edit.Text+'"'); WebEdit1.Text := newform.frm2Edit.Text; finally newform.Free; end; end;
Oh, and of course, the same applies to the upcoming TMS WEB Core for Visual Studio Code.
We look forward to your feedback & comments! Happy coding meanwhile.
Learn more about TMS WEB Core 1.7 Ancona?
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post