From f7b5c9af3e4b5edaf91722429495182d97fde397 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Mon, 14 Apr 2014 14:44:30 +0300 Subject: [PATCH] Promises added and implemented experimentally in WebClient --- BCL.csproj | 2 + Promises/index.ts | 2 + Promises/promises.ts | 114 ++++++++++++++++++++++++++++++++++++ WebClient/web_client.d.ts | 8 +-- WebClient/web_client.ios.ts | 20 ++++++- 5 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 Promises/index.ts create mode 100644 Promises/promises.ts diff --git a/BCL.csproj b/BCL.csproj index 06c4ab108..5fbc893ce 100644 --- a/BCL.csproj +++ b/BCL.csproj @@ -146,6 +146,8 @@ + + console.d.ts diff --git a/Promises/index.ts b/Promises/index.ts new file mode 100644 index 000000000..a26b560fd --- /dev/null +++ b/Promises/index.ts @@ -0,0 +1,2 @@ +declare var module, require; +module.exports = require("Promises/promises"); \ No newline at end of file diff --git a/Promises/promises.ts b/Promises/promises.ts new file mode 100644 index 000000000..c675e5583 --- /dev/null +++ b/Promises/promises.ts @@ -0,0 +1,114 @@ +export module Promises { + + export function when(...promises: Promise[]): Promise { + var all_done = new Deferred(); + var results = []; + var remaining = promises.length; + + promises.map( + (p, i) => { + p.then( + function (...args: any[]) { + results[i] = args; + remaining--; + if (!remaining && all_done.status() !== 'rejected') { + all_done.resolve.apply(all_done, results); + } + }, + function () { all_done.reject() } + ); + } + ); + + if (!remaining) { + all_done.resolve.apply(all_done, results); + } + + return all_done.promise(); + } + + export class Promise { + + constructor(private deferred: Deferred) { } + + then(callback: Function, error: Function): Promise { + return this.deferred.then(callback, error); + } + + status(): string { return this.deferred.status() } + result(): any[] { return this.deferred.result() } + } + + export class Deferred { + + private resolved: Function[] = []; + private rejected: Function[] = []; + private _status: string; + private _result: any[]; + private _promise: Promise; + + constructor() { + this._promise = new Promise(this); + this._status = 'in progress'; + } + + promise(): Promise { return this._promise } + status(): string { return this._status } + result(): any[] { return this._result } + + resolve(...result: any[]): Deferred { + this._result = result; + this.notify(this.resolved, result); + this.resolved = []; + this._status = 'resolved'; + return this; + } + + reject(...result: any[]): Deferred { + this._result = result; + this.notify(this.rejected, result); + this.rejected = []; + this._status = 'rejected'; + return this; + } + + then(callback: Function, error: Function): Promise { + var d = new Deferred(); + + this.resolved.push(this.wrap(d, callback, 'resolve')); + + if (error) { + this.rejected.push(this.wrap(d, error, 'reject')); + } + + if (this._status === 'resolved') { + this.resolve.apply(this, this.result); + } + else if (this._status === 'rejected' && error) { + this.reject.apply(this, this.result); + } + + return d.promise(); + } + + private wrap(d: Deferred, f: Function, method: string): Function { + return function (...args: any[]) { + var result = f.apply(f, args); + if (result && result instanceof Promise) { + result.then( + function () { d.resolve() }, + function () { d.reject() } + ); + } + else { + d[method].apply(d, typeof result === 'array' ? result : [result]); + } + } + } + + private notify(funcs: Function[], result: any[]): void { + funcs.map((f) => { f.apply(f, result) }); + } + } + +} \ No newline at end of file diff --git a/WebClient/web_client.d.ts b/WebClient/web_client.d.ts index 22b625121..609e80bf3 100644 --- a/WebClient/web_client.d.ts +++ b/WebClient/web_client.d.ts @@ -4,8 +4,8 @@ import image_module = require("Image/image"); export declare class Client { - private static get(url: string, successCallback: (result: any) => void, errorCallback?: (e: Error) => void) - getString(url: string, successCallback: (result: string) => void, errorCallback?: (e: Error) => void) - getJSON(url: string, successCallback: (result: Object) => void, errorCallback?: (e: Error) => void) - getImage(url: string, successCallback: (result: image_module.Image) => void, errorCallback?: (e: Error) => void) + private static get(url: string, successCallback?: (result: any) => void, errorCallback?: (e: Error) => void) + getString(url: string, successCallback?: (result: string) => void, errorCallback?: (e: Error) => void) + getJSON(url: string, successCallback?: (result: Object) => void, errorCallback?: (e: Error) => void) + getImage(url: string, successCallback?: (result: image_module.Image) => void, errorCallback?: (e: Error) => void) } \ No newline at end of file diff --git a/WebClient/web_client.ios.ts b/WebClient/web_client.ios.ts index 5a2023771..b9a393342 100644 --- a/WebClient/web_client.ios.ts +++ b/WebClient/web_client.ios.ts @@ -3,6 +3,7 @@ */ import image_module = require("Image/image"); +import promises_module = require("Promises/promises"); export class Client { /** @@ -22,6 +23,12 @@ export class Client { } } + public static getString(url : string) { + var d = new promises_module.Promises.Deferred(); + new Client().getString(url, r => d.resolve(r), e => d.reject(e)); + return d.promise(); + } + public getJSON(url: string, successCallback: (result: Object) => void, errorCallback?: (e: Error) => void) { try { this.getString(url, function (data) { @@ -46,7 +53,18 @@ export class Client { }, errorCallback); } - private static get(url: string, successCallback: (result: any) => void, errorCallback?: (e: Error) => void) { + private static get(url: string, successCallback?: (result: any) => void, errorCallback?: (e: Error) => void) { + if (!successCallback && !errorCallback) + { + var d = new promises_module.Promises.Deferred(); + Client.getUrl(url, r => d.resolve(r), e => d.reject(e)); + return d.promise(); + } + + Client.getUrl(url, successCallback, errorCallback); + } + + private static getUrl(url: string, successCallback: (result: any) => void, errorCallback?: (e: Error) => void) { try { var sessionConfig = Foundation.NSURLSessionConfiguration.defaultSessionConfiguration(); var queue = Foundation.NSOperationQueue.mainQueue();