Jump to content

Search the Community

Showing results for tags 'promise'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Categories

There are no results to display.

Forums

  • Welcome to Smart Mobile Studio
    • News and Information
    • Pre-Sales Questions
    • Smart In the Media
    • Smart Contests
    • Meta
  • Smart Mobile Studio Discussion
    • General
    • IDE
    • RTL
    • Code
    • Client Server
    • Platform
    • Graphics
    • Deployment
    • Suggestion box
  • Smart Mobile Studio support
    • Support
    • Bug report
  • General Discussion
    • Pascal
    • Delphi
    • Javascript
    • HTML/HTML5
    • CSS
  • Resources
    • Website
    • Download Smart Mobile Studio

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website URL


Location


Interests


Company name


Position

Found 2 results

  1. lynkfs

    Promises revisited

    Promises are a javascript construct enabling async processes to be written in a synchronous manner (sort of). The status quo at this stage : - Promises are part of javascript since Ecmascript 6 - Promises are enabled in all major browsers - Promises work in node.js too (require('promise')) - Promises are not used in the rtl, or described in Smart documentation - There have been some posts on the forum re implementing promises (the best one : ) - The ecma.promise unit in the rtl is based on an older, incompatible, version of the current spec The subject of this post is to try and make the ecma.promise unit usable again and provide some examples A promise is a way to combine an asynchronous action, its possible outcomes and the actions associated with these outcomes in a single construct. Reading through the API documents (see bottom of this post), the basic syntax to create a promise is : var promise : variant := new JPromise(resolver) where resolver is a function with as arguments a resolve and reject function, which resolves the promise or rejects it on error. The return value of the resolver itself is ignored. (so we might as well type it as a procedure rather than a function) The above is covered by type TPromiseCallback = function(Value: Variant): Variant; JPromise = class external 'Promise' public constructor Create(resolver: procedure(resolve,reject: TPromiseCallback)); end; The most important functions of the Promise object are the "then" and the "catch" functions. Basically these are used to process actions when the promise is either resolved or rejected. So we need to add at least this to the type info type JPromise = class external 'Promise' public ... function &then(onFulFilled: TPromiseCallback): Variant; function catch(onRejected: TPromiseCallback): Variant; end; Some examples The most quoted example is an external httprequest for some data (1), wait for the request to come back and see if it was succesfull or not (2) and perform the necessary actions (3) or (4). function example1(url:string):variant; begin var q : variant := new JPromise(procedure(resolve,reject: TPromiseCallback) begin var FHttp := TW3HttpRequest.Create; FHttp.GET(url); //1 do something asynchronous FHttp.ondataready := lambda resolve(FHttp.responseText); end; //2 resolve (and pass 'responseText' on to the then function) FHttp.onerror := lambda reject(FHttp.statusText); end; reject (and pass 'statusText' on to the catch function) end) .then(function(x:variant):variant begin writeln(x); end) //3 do something when succesful .catch(function(x:variant):variant begin writeln(x); end); //4 do something when unsuccesfull result := q; end; Example1('res/textfile.txt'); Really not that different from a normal ajax call : procedure example2(url:string); begin procedure OnDataReady(x: variant); begin writeln(x) end; //3 procedure OnError(x: variant); begin writeln(x) end; //4 var FHttp := TW3HttpRequest.Create; FHttp.GET(url); //1 FHttp.ondataready := lambda OnDataReady(FHttp.responseText) end; //2 FHttp.onerror := lambda OnError(FHttp.statusText) end; end; Example2('res/textfile.txt'); The differences being here that promises allow all code in the one construct. The other main advantage is that a single promise can be accessed multiple times and at multiple code locations: Suppose we have a promise which reads an accountname from a db, and the accountname is say displayed on a window title and a report. In both places this can be simply referred to as AccountName = AccountPromise.then(*function*) without having to check if data is actually available. The promise api also provides a shortcut to create a promise in the resolved or rejected state immediately without going through its constructor : Promise.resolve('resolved'); Promise.reject('rejected'); For this we need access to the global Promise object, and have to add the next line : type ... var Promise external 'Promise': variant; A possible use is if we have a process consisting of multiple steps, and we want to use the chaining mechanism of the "then" functions of the promise object to tie these steps together : Promise.resolve('life') //life .then(function(x:variant):variant begin result := x + "'s"; //life's end) .then(function(x:variant):variant begin writeln(x + ' good'); //life's good end); The two remaining api functions are promise = Promise.all(array or set) promise = Promise.race(array or set) These functions are initially typed as JPromise = class external 'Promise' public ... function all(Iterable: variant): Variant; function race(Iterable: variant): Variant; end; Both can be used when running asynchronous tasks in parallel. Suppose there are say 3 tasks running concurrently which execute a query to Google, Bing and Yahoo The "all" function returns a promise when all 3 promises have been resolved, and the "race" function as soon as one of the promises has been resolved Promise.all(requests:array[0..2] of string) .then(function(outcome:variant):variant begin writeln('All ' + requests.length + ' query outcomes received'); end); .catch(function(error:variant):variant begin writeln('Error occurred ' + error); end); Adding it all up, the typed info as per below works perfectly fine for the type of examples listed above type TPromiseCallback = function(Value: Variant): Variant; JPromise = class external 'Promise' public constructor Create(resolver: procedure(resolve,reject: TPromiseCallback)); function &then(onFulFilled: TPromiseCallback): Variant; function catch(onRejected: TPromiseCallback): Variant; function all(Iterable: variant): Variant; function race(Iterable: variant): Variant; end; var Promise external 'Promise': variant; To complicate matters a bit, and usually unnecessarily so : The function header of the "then" function above is the most used format. "Then" is however actually a function with 2 arguments, both of which are optional. Which means that the possible formats of this function are function &then: Variant; overload; function &then(onFulFilled: TPromiseCallback): Variant; overload; function &then(onFulfilled, onRejected: TPromiseCallback): Variant; overload; Mozilla : "If one or both arguments are omitted or are provided non-functions, then they will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, a new Promise is created with no additional handlers, simply adopting the final state of the original Promise on which then was called". My thoughts exactly () By the way this also means that catch(onRejected) is the same as &then(undefined, onRejected); Another (usually unnessary) detail is that the static resolve function (Promise.resolve) comes in different flavours as well : Promise.resolve(promise); Returns promise (only if promise.constructor == Promise) Promise.resolve(thenable); Make a new promise from the thenable. A thenable is promise-like in as far as it has a `then() method. Promise.resolve(obj); Make a promise that fulfills to obj. in this situation. This however is handled by the reference to the global Promise object, and doesn't require any changes to the typed info Finally, Mozilla also lists a "finally" function, which is not described in other api documents API documentation http://definitelytyped.org/docs/es6-promises--es6-promises/classes/promise.html https://tc39.github.io/ecma262/#sec-promise-constructor https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://promisesaplus.com/ https://developers.google.com/web/fundamentals/primers/promises#promise-api-reference https://github.com/tildeio/rsvp.js Note: In principal there are 3 ways to extract and type the functions, procedures and variables from any API : - find an API declaration file and convert this programmatically into object Pascal syntax - find a reference to a global object representing the API methods (if available) - read through the API specs The first option would involve finding a relevant API declaration file (f.i. this one) and convert this into pascal syntax. The results of using ts2pas (see posts) have been not very 'promising' The second option, when using promises in a browser environment, is to simply forget about typing, but have a reference to the global window object, and reference the promise object from there : var window external 'window': variant; ... var promise := window.Promise.resolve('something'); promise.then(function(x:variant):variant begin writeln(x); end); The post above has used the last option (read the API docs) Surprisingly, it is actually somewhat difficult to find the latest/most comprehensive/most agreed upon spec. The promise api has gone through various iterations, starting from an idea to external libraries (Q, when, rsvp.js) and finally becoming part of the javascript language in Ecmascript 6. Even then there have been some changes . Please let me know if you know of relevant use cases for this API requiring other changes to the ECMA.Promise unit
  2. lynkfs

    ecma.promise

    Does anyone know how to use the Ecma.Promise unit ? Looks like the external PromiseInit ref doesn't exist
×