Promises/A+ implementation in Sciter2

The Promises, as a concept, is generalization of callback mechanism. This pattern is quite popular these days so Sciter2 SDK contains now (sdk/samples/+promise/) pretty simple (60 lines of code) implementation of the Promises.

The promise is an object that:

  1. maintins list/chain of callback function pairs [onsuccess:function, onfailure:function] by providing .then(onsuccess, onfailure) method;
  2. promise object provides the way to "execute" the chain, either succes or failure callbacks (if an error occurs);
  3. each callback function in the chain receives input (parameters) from output (return [values]) of previous callback in the chain.

To create the promise in Sciter simply do this:

var oath = promise();

The promise() function and promise object

The promise() function in my implementation returns function/object that has .then() method defined on it. So to attach callback functions to the promise you will do this:

oath.then( function( data ) { return [data+1] } ) // #1
    .then( function( data ) { return [data+2] } ) // #2
    .then( function( data ) { stdout.println("success:", data)}, // #3 
           function( reason ) { stderr.println("error:", reason)} );

Now we have promise in variable oath that has three onsuccess functions assigned to it.

When time comes for the promise to be fulfilled, our code will do it by invoking the promise (as it is a function) with its first parameter set to true and with additional parameters that will be passed to the first callback in the chain:

oath(true, 1);

This will call first callback with 1 in data. It will return 1 + 1 -> 2.
That 2 value will be passed to second callback that will return 2 + 2 -> 4.
And finally last callback will just do println:


To reject the promise we just need to call it with first parameter set to false:

oath(false, "something went wrong!");

This will call our sole onerror callback and we will get:

error: something went wrong!

The promise.when() function, parallel execution

The promise has also defined static function promise.when(...)  that accepts list of promises and return another promise that will be fullfilled/rejected when all input promises will be completed.

function printBandC(b,c) { stdout.println(b,c) }

var BandC = 
    promise.when( self.request(#get-json, urlB),
                  self.request(#get-json, urlC)).then(printBandC);

There are quite many articles about the subject, just google for “Promises JavaScript”

Here is the full source of promise.tis module:

Read more…

Sciter UI, basic principles. Calling code behind UI from worker threads.

I’ve updated the SDK with new sample: /sdk/demos/ui-framework .
This sample demonstrates principles outlined in “Sciter UI, application architecture” article.

Sciter demo screenshot

In particular it demonstrates definition of native function (view.execTask() -> window::exec_task()) and call of UI methods (callbacks in this sample) from worker threads.

I’ve explained idea of calling UI code from worker threads in this article but in this demo I am using slightly different mechanism.

The gui_exec function looks like this:

// this function is called from worker threads to 
// execute the gui_block in GUI thread
inline void gui_exec( std::function<void()> gui_block )
  sciter::sync::event evt;
  PostThreadMessage(gGUIThreadId, WM_EXEC, WPARAM(&evt),LPARAM(&gui_block));
  evt.wait(); // suspend worker thread until GUI will execute the block.

It posts the message into GUI thread input queue. Receiver of WM_EXEC message is Windows WH_GETMESSAGE hook function:

// message hook to handle WM_EXEC in GUI thread
static LRESULT CALLBACK gui_exec_hook_GetMsgProc(int code, WPARAM wParam, LPARAM lParam )
  MSG* pmsg = reinterpret_cast<MSG*>(lParam);
  if(pmsg->message == WM_EXEC)
    sciter::sync::event* pe = reinterpret_cast<sciter::sync::event*>(pmsg->wParam);
    gui_block* pf = reinterpret_cast<gui_block*>(pmsg->lParam);
    (*pf)();      // execute the block in this GUI thread
    pe->signal(); // signal that we've done with it
                  // this will resume execution of worker thread.
  return CallNextHookEx(0,code, wParam,lParam);

Using hooks allows this mechanism to work reliably even when application is running modal dialog loops.