• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Sequential Code for Async Cloud Requests with Delphi Promises!

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,486
Баллы
155
Asynchronous programming is crucial for modern applications, but managing multiple callbacks and events can quickly turn into a tangled mess—commonly known as "callback hell". But the very need for asynchronous calls is to avoid GUI thread freezes when for example HTTP requests take an unpredictable amount of time. To tackle this challenge, we are excited to introduce beta support for promises in

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

! With promises, you can write clean, sequential code for cloud-based operations while maintaining all the benefits of asynchronous behavior.

The Challenge
TMS Software Delphi  Components


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

relies on asynchronous requests to communicate with various cloud services, such as Google, PayPal,

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, and more. If you've worked with our components, you’re familiar with how asynchronous communication is handled via callbacks and events.

While effective, this approach can become difficult to manage. For example, to view an event from the Google Calendar API, you need to go through all these steps:
  1. Authenticate the user.
  2. Retrieve a list of available calendars.
  3. Fetch the events for a specific calendar.
Using callbacks and events for such workflows can quickly spiral into complexity, making the code harder to read, maintain and debug.

Promising Solution


Being so used to using promises in the context of web applications, where by design, several functions work asynchronously, we missed a promises implementation for a long time for native Delphi code. Especially in the area of using REST API functions, the ability to use promises significantly simplifies writing code that needs to be built with chained asynchronous calls.

It was with much enthusiasm that we discovered the promises library written by Laurens van Run from

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

earlier this year. This triggered us to get in touch with Laurens and see how we could both spread the message about this fantastic new Delphi promises library and also leverage this in the context of our components, especially the TMS FNC Cloud Pack that is built on top of asynchronous REST APIs.

By working together with Laurens, we also contributed to make his promises library cross-platform and offer it integrated as part of TMS FNC Core to make using it from TMS FNC Cloud Pack as seamless as possible.

We thank Laurens so much for all his efforts that went into this. Laurens did a great job for the Delphi community and his promises library is not the only one. Laurens also actively contributes to projects like

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

and

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

. And Laurens also revitalized the (old) Delphi

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

plugin and worked with Embarcadero to bring attention to it.

Together with his colleagues at Mendrix and the Delphi community, Laurens drives forward innovation in the Delphi world. Check also what jobs Mendrix has to offer for Delphi developers here:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.




Example

Let’s break down a small example to understand the building blocks of using promises. In this example, we’ll request the bordering countries of a given country using the

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

. The API returns an array of country codes for the bordering nations, so we’ll need to make additional requests to retrieve their full names.

1. Deferred Promises
The core mechanism relies on deferred promises, which are created using

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

. This method takes an executor function as a parameter. The executor function provides two parameters, AResolve and AReject, which allow you to resolve or reject a promise after an asynchronous operation completes. These parameters can be persisted and invoked later or used in a callback directly:

//We will query two endpoints:
//https://restcountries.com/v3.1/name/{CountryName}
//https://restcountries.com/v3.1/alpha/{CountryCode}
//Create a common request method that we can reuse
function TForm1.ExecuteRestCountryRequest(APath: string; ACountryOrCode: string): IPromise<string>;
begin
Result := Promise.New<string>(procedure (AResolve: TProc<string>; AReject: TProc<Exception>)
begin
c.Request.Clear;
c.Request.Host := '

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


c.Request.Method := rmGET;
c.Request.Path := APath + '/' + ACountryOrCode;
c.Request.ResultType := rrtString;
c.ExecuteRequest(procedure (const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
if ARequestResult.Success then
AResolve(ARequestResult.ResultString)
else
AReject(Exception.Create('Request failed. No country or code found: ' + ACountryOrCode));
end);
end);
end;

2. Chaining
TMS Software Delphi  Components

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

ensures sequential execution of operations while preserving asynchronous behavior. Each .ThenBy call returns a new IPromise<T> and defines what happens after the current promise resolves. The value returned from each step is passed to the next in the chain, reducing the need for nested callbacks.

A simple example on chaining:

function TForm1.GetCountryNameFromCode(ACode: string): IPromise<string>;
begin
Result := ExecuteRestCountryRequest('/alpha', ACode)
.ThenBy(function (const AValue: string): string
begin
//AValue contains the JSON response, parse it to get the name:
Result := GetCountryNameFromJSON(value);
end);
end;
In the snippet above, ExecuteRestCountryRequest is used to make an API call, and the response is parsed in a chained step to extract the desired data&#151;in this case, the country name.

3. Chain multiple deferred promises
Understanding this step is important before moving on to the final step of waiting for multiple deferred promises to complete.
It might seem a bit complex at first glance, but combining multiple deferred promises with chaining is actually simple. The key to understanding this is that a promise is resolved when the Result is set. This means we need to return a promise from the .ThenBy method, ensuring that the chain continues only after the current promise has been resolved.

Here&#146;s how it works in practice:

Promise.New<TVoid>(procedure(AResolve: TProc<TVoid>; AReject: TProc<Exception>)
begin
//Do the first promisified call
end)
.ThenBy(function(const AResult: TVoid): IPromise<TVoid>
begin
Result := Promise.New<TVoid>(procedure(AResolve: TProc<TVoid>; AReject: TProc<Exception>)
begin
//Do the second promisified call
end);
end)
.ThenBy(function(const AResult: TVoid): IPromise<TVoid>
begin
Result := Promise.New<TVoid>(procedure(AResolve: TProc<TVoid>; AReject: TProc<Exception>)
begin
//Do the third promisified call
end);
end);

4. Wait for multiple promises

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

allows us to wait for multiple promises to resolve, and we can apply the same logic as before. The key difference is that, instead of returning a single IPromise<T>, we now return an array of them:

procedure TForm1.GetBorderingCountires(ACountry: string);
begin
//Start by getting the country name
ExecuteRestCountryRequest('/name', ACountry)
.Op.ThenBy<TArray<string>>(function (const AValue: string): IPromise<TArray<string>>
var
LBorders: TArray<string>;
LPromises: TArray<IPromise<string>>;
I, LBorderCount: Integer;
begin
//Parse the returned JSON to retrieve the list of
//bordering countries
LBorders := GetBorderingCountriesFromJSON(AValue);
LBorderCount := Length(LBorders);
SetLength(LPromises, LBorderCount);

//Create a promise for each country code, these are individual
//requests:
for I := 0 to LBorderCount - 1 do
LPromises := GetCountryNameFromCode(LBorders);

//Wait for all the promises to complete
Result := Promise.All<string>(LPromises);
end)
.Main.ThenBy<TVoid>(function (const AValues: TArray<string>): TVoid
var
I: Integer;
begin
//Cautiously update the UI reflecting the list:
if FFormNotDestroyed then
begin
for I := 0 to Length(AValues) - 1 do
Memo1.Lines.Add(AValues);
end;

Result := Void;
end)
.Main.Catch(procedure (E: Exception)
begin
//Show errors - if any:
ShowMessage(E.Message);
end);
end;
And that&#146;s it! By calling GetBorderingCountries from a button click, you&#146;ll fetch the list of neighboring countries while keeping the UI responsive.

Get Started and Share Your Feedback

If you'd like to see something more practical, particularly in combination with our TMS FNC Cloud Pack components, take a look at the TTMSFNCCloudGoogleCalendar demo we&#146;ve prepared, available under the Demo\Promises folder! It not only demonstrates the concepts discussed above but also shows how to keep your codebase cleaner by inheriting from TTMSFNCCloudGoogleCalendar and handling promises internally.

While awaiting that Christmas dinner to bake in the oven, take a moment to explore how promises can simplify your workflows and make your code more maintainable. The implementation of promises is now available for registered users, integrated into TMS FNC Core as a BETA! To make the most of the Delphi-Promises library, be sure to

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

, which offers detailed guidance to help you get started quickly.

The integration requires Delphi 10.2 or later, so ensure your development environment meets the minimum requirements.

Your feedback will play a valuable role in shaping the future of promises within our FNC range. Dive into the BETA, try it out, and let us know how promises are impacting your development experience!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу