Skip to content

Commit

Permalink
Merge pull request #6 from feugy/enhanced-proxy-perf
Browse files Browse the repository at this point in the history
Enhance proxy performances
  • Loading branch information
feugy committed Nov 5, 2016
2 parents 4ccc6d8 + ba1cbf0 commit ae54e3b
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 7 deletions.
13 changes: 8 additions & 5 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ class Client {

const {logger, remote} = this.options

return remote ? new Proxy(this, {
const traps = {
get(target, propKey) {
// use first defined properties
if (propKey in target) {
return target[propKey]
// init() is the only operation callable while proxy is still active
if (propKey === 'init') {
return target.init
}
// reserved keyword that aren't defined must be undefined (thenable false-positive)
if (reserved.includes(propKey)) {
Expand All @@ -56,6 +56,8 @@ class Client {
logger.debug(`during ${propKey}, connect to ${remote} to get exposed apis`)
return registerFromServer(target, remote, logger)
.then(() => {
// delete trap to boost performance: next calls will directly search into 'this'
delete traps.get
logger.debug('remote client ready')
// now, invoke the API with initial arguments, but only if it exists
if (!(propKey in target)) {
Expand All @@ -65,7 +67,8 @@ class Client {
})
}
}
}) : this
}
return remote ? new Proxy(this, traps) : this
}

/**
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"request-promise": "4.0.2"
},
"devDependencies": {
"benchmark": "2.1.1",
"coveralls": "2.11.11",
"eslint": "3.0.1",
"ghooks": "1.2.4",
Expand Down
50 changes: 50 additions & 0 deletions proxy-benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict'

const benchmark = require('benchmark')
const list = [1, 2, 3, 4, 5]

const sum = () => {
let total = 0
for (let i = 0; i < list.length; i++) {
total += list[i]
}
return total
}

// simple object
const obj = {sum}

// proxy that wraps an empty object
const emptyProxy = new Proxy({}, {
get(target, key) {
if (key === 'sum') {
return obj.sum
}
return undefined // eslint-disable-line no-undefined
}
})

// no-op proxy around
const noopProxy = new Proxy(obj, {})

// one-time proxy
const handler = {
get(target, key) {
target.sum = sum
delete handler.get
return target[key]
}
}
const oneTimeProxy = new Proxy({}, handler)

new benchmark.Suite().add('normal method', () =>
obj.sum()
).add('proxy', () =>
emptyProxy.sum()
).add('no-op proxy', () =>
noopProxy.sum()
).add('one time proxy', () =>
oneTimeProxy.sum()
).on('cycle', ({target}) =>
console.log(target.toString()) // eslint-disable-line no-console
).run()
59 changes: 58 additions & 1 deletion test/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ const Lab = require('lab')
const assert = require('power-assert')
const moment = require('moment')
const bunyan = require('bunyan')
const request = require('request-promise')
const {getClient, startServer} = require('../')
const {version} = require('../package.json')
const utils = require('./utils')
const utils = require('./test-utils')

const lab = exports.lab = Lab.script()
const {describe, it, before, beforeEach, after} = lab
Expand Down Expand Up @@ -125,6 +126,62 @@ describe('service\'s client', () => {
after(() => server.stop())

declareTests(context)

it('should not add too much overhead', {timeout: 15e3}, () => {

const benchmark = {
client: () => context.client.greeting('Jane'),
direct: () => request({
method: 'POST',
uri: `${server.info.uri}/api/sample/greeting`,
body: {name: 'Jane'},
json: true
})
}
const run = (name, results, start, duration) => {
const end = () => {
if (Date.now() - start >= duration) {
return Promise.resolve()
}
return run(name, results, start, duration)
}

return benchmark[name]()
.then(() => {
results.count++
return end()
})
.catch(err => {
results.errored++
results.errors.push(err)
return end()
})
}

const runBench = (names, results = {}) => {
if (names.length === 0) {
return Promise.resolve(results)
}
const name = names.shift()
results[name] = {count: 0, errored: 0, errors: []}
// heating run
return run(name, {count: 0, errored: 0, errors: []}, Date.now(), 1e3)
// test run
.then(() => run(name, results[name], Date.now(), 5e3))
// next bench
.then(() => runBench(names, results))
}

return runBench(Object.keys(benchmark))
.then(results => {
const percentage = results.client.count * 100 / results.direct.count
assert(results.direct.count > 1000)
assert(results.client.count > 1000)
assert.equal(results.direct.errored, 0)
assert.equal(results.client.errored, 0)
assert(percentage >= 80)
})
})
})

describe('a remote client without server', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const bunyan = require('bunyan')
const assert = require('power-assert')
const request = require('request-promise')
const {startServer} = require('../')
const utils = require('./utils')
const utils = require('./test-utils')

const lab = exports.lab = Lab.script()
const {describe, it, before, beforeEach, after, afterEach} = lab
Expand Down
File renamed without changes.

0 comments on commit ae54e3b

Please sign in to comment.