Notes-03-28-digital-signing-webpack-dynamic-import-JsonRest-Promise-pattern-performance.measure()

Digital Signing

Terms:

digest: hash of the doc

Normal flow:

Sender

var digest = hash(doc);
send({ 
    counterpart: doc.copy(), 
    encryption: encrypt(digest)
})

Receiver

var digestByCounterpart = hash(counterpart);
var digest = decrypt(encryption);
isEqual(
    digestByCounterpart,
    digest
);

With CA:

Sender

var certificate = encryptByCA({
    senderPublicKey,
    senderinfo
}); 

var digest = hash(doc);
send({ 
    counterpart: doc.copy(), 
    encryption: encrypt(digest)
    certificate
})

Receiver

isEqual(
    decryptCA(certificate), 
    { senderPublicKey, senderInfo }
);
isEqual(
    hash(counterpart),
    decrypt(encryption)
);

Keys

  • CA need to be trusted

  • TODO

Webpack Dynamic Import

  1. Use import(${path}), webpack resolves it in a jsonp way

  2. webpack will do code splitting (generate different bundle) for each module that is NOT in the dependency tree of App.js (not imported yet)

  3. webpack will download the splitted js file when imported is called

  4. webpack uses webpackJsonp() as a global callback to inject the module into the main bundle (main dependency tree)

  5. Once the dynamic import is done, the next same import will be static

  6. if the dynamic imported file is already in main dependency tree(be imported my some other file), it will not be code splitted, dynamic import will be transformed to static as 5 does

Promise pattern JSONRest

private subscriberPublicGroupStores: { [subscriberId: string]: JsonRest } = {};

private getSubscriberPublicGroupStore = (subscriberId: string) => {
  const subscriberPublicGroupStores = this.subscriberPublicGroupStores;

  if (subscriberId in subscriberPublicGroupStores) {
    return subscriberPublicGroupStores[subscriberId];
  } else {
    const encodedSubscriberId = encodeURIComponent(subscriberId);
    return (subscriberPublicGroupStores[subscriberId] = new JsonRest<Array<LookupItemModel>>({
      url: `/Workspaces/public-groups/subscribers/${encodedSubscriberId}`,
      immediate: true
    }));
  }
};
class JsonRest<R = any> {
  private url: string;
  private immediate: boolean = true;
  private data?: Promise<R>;
  private subscribers: { resolve: Array<Function>; reject: Array<Function> } = { resolve: [], reject: [] };

  constructor(config: string | Config<R>) {
    if (typeof config === 'string') {
      this.url = config;
    } else {
      this.url = config.url;
      this.immediate = config.immediate;
    }

    if (this.immediate) {
      this.query();
    }
  }

  public query = (): Promise<R> => {
    if (!this.data) {
      this.data = http.get<R>(this.url);
    }
    return this.data!.then(data => {
      this.subscribers.resolve.forEach(fn => fn(data));
      return data;
    }) //
      .catch(err => {
        this.subscribers.reject.forEach(fn => fn(err));
        throw err;
      });
  };

  public subscribe(event: SubscriptionType, callback: Function) {
    this.subscribers[event].push(callback);

    return () => {
      this.subscribers[event] = this.subscribers[event].filter(fn => fn !== callback);
    };
  }
}
class SelectField extends BaseField<{}> {
  private _unsubscribe?: Function;

  componentWillReceiveProps(props: any) {
    // remove previouse subscription
    if ((this.props as any).store !== props.store && this._unsubscribe) {
      this._unsubscribe();
      this._unsubscribe = undefined;
    }
  }

  componentWillUnmount() {
    this._unsubscribe && this._unsubscribe();
  }

  render() {
    const props = this.resolveComponentProps();
    if (props.preSelectFirst && props.store) {
      if (!this._unsubscribe) {
        this._unsubscribe = props.store.subscribe('resolve', (items: Array<any>) => {
          const {
            form: { setFieldValue },
            field: { value }
          } = this.props;

          // Check the previous value
          // If there is no value, pre-select if the dropdown only has one option
          // Otherwise check if the drop down contains current selected option
          // TODO: Posibily improve logic
          if (!value) {
            if (items.length === 1) {
              setFieldValue(props.name, items[0].id);
            }
          } else if (items.findIndex(item => item.id === value) === -1) {
            setFieldValue(props.name, '');
          }
        });
      }
    }

    return <Select {...props} />;
  }
}

Promise Pattern

sync Promise

In runkit:

var { SynchronousPromise } = require("synchronous-promise");
console.log('init');
var as = new Promise((resolve, reject) => { resolve('happy as!'); });
as.then(message => { console.log(message); });
console.log('block1');
var initial = new SynchronousPromise((resolve, reject) => { resolve('happy!'); });
initial.then(message => { console.log(message); });
console.log('end');

will print out:

init
block1
happy! // sync
end
happy as! // async

chaining

Reference Link

function logFail(v) {
  console.log('fail' + v);
}
function logSuccess(v) {
  console.log('success' + v);
}
var a = new Promise( resolve => {
  resolve(1);
}).then(r => {
    logSuccess(r);
    return r + 1;
}).catch(e => {
    logFail(e);
    throw e;
}).then(r => {
    logSuccess(r);
    throw r + 1;
}).catch(e => {
    logFail(e);
    throw e;
}).then(r => {
    logSuccess(r);
    throw r + 1;
}).catch(e => {
    logFail(e);
    return e + 1;
}).then(
    r => {
      logSuccess(r);
      throw r + 1;
    },
    e => {
      logFail(e);
      throw e;
    }
).catch(e => {
    logFail(e + ' catch and error in then is different');
});

will output

success1
success2
fail3
fail3
success4
fail5 catch and error in then is different

Measure Regexp

function measurePerformance(name, callback) {
  performance.mark(`${name}-start`);
  const res = callback();
  performance.mark(`${name}-end`);
  performance.measure(name, `${name}-start`, `${name}-end`);
  const entries = performance.getEntriesByName(name);
  const latestMeasure = performance.getEntriesByName(name)[entries.length - 1];
  console.debug(`${name} milliseconds:`, latestMeasure.duration);
  console.debug(latestMeasure);
  return res;
}

Regex check

with create regex everytime

measurePerformance('1', () => /^[0-9]{5,10}$/.test('1111'));
// 1 milliseconds: 0.11999998241662979
// 1 milliseconds: 0.12999994214624166
// 1 milliseconds: 0.16499997582286596

with cached regex object

const cachedReg = /^[0-9]{5,10}$/;
measurePerformance('1', () => cachedReg.test('1111'));
// 1 milliseconds: 0.024999957531690598
// 1 milliseconds: 0.029999995604157448

// Change test value
measurePerformance('1', () => cachedReg.test('11112'));
// 1 milliseconds: 0.024999957531690598

for manual check

measurePerformance('1', () => isNaN('11111') && '11111'.length > 5 && '11111'.length < 10);
// 1 milliseconds: 0.030000112019479275
// 1 milliseconds: 0.059999991208314896
// 1 milliseconds: 0.024999957531690598

Last updated