New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite Got #1051
Rewrite Got #1051
Changes from all commits
fcb2329
1e8cd40
d85bc21
394c834
025f4f2
7645711
d64298c
a8c18bb
c9e3472
aba2c29
467f80b
be086da
04821b9
ff197c1
827eaf0
5619b26
ab273e6
841ddda
822bf88
3f7aacd
3a15eb8
a76bb61
6912f0c
b9f0592
0d6b958
84467bf
d84cc03
90edfd1
e4ac3a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
'use strict'; | ||
import {URL} from 'url'; | ||
import https = require('https'); | ||
import axios from 'axios'; | ||
import Benchmark = require('benchmark'); | ||
import fetch from 'node-fetch'; | ||
import request = require('request'); | ||
import got from '../source'; | ||
import PromisableRequest from '../source/as-promise/core'; | ||
import Request, {kIsNormalizedAlready} from '../source/core'; | ||
|
||
const {normalizeArguments} = PromisableRequest; | ||
|
||
// Configuration | ||
const httpsAgent = new https.Agent({ | ||
keepAlive: true, | ||
rejectUnauthorized: false | ||
}); | ||
|
||
const url = new URL('https://127.0.0.1:8080'); | ||
const urlString = url.toString(); | ||
|
||
const gotOptions = { | ||
agent: { | ||
https: httpsAgent | ||
}, | ||
rejectUnauthorized: false, | ||
retry: 0 | ||
}; | ||
|
||
const normalizedGotOptions = normalizeArguments(url, gotOptions); | ||
normalizedGotOptions[kIsNormalizedAlready] = true; | ||
|
||
const requestOptions = { | ||
strictSSL: false, | ||
agent: httpsAgent | ||
}; | ||
|
||
const fetchOptions = { | ||
agent: httpsAgent | ||
}; | ||
|
||
const axiosOptions = { | ||
url: urlString, | ||
httpsAgent, | ||
rejectUnauthorized: false | ||
}; | ||
|
||
const axiosStreamOptions: typeof axiosOptions & {responseType: 'stream'} = { | ||
...axiosOptions, | ||
responseType: 'stream' | ||
}; | ||
|
||
const httpsOptions = { | ||
rejectUnauthorized: false, | ||
agent: httpsAgent | ||
}; | ||
|
||
const suite = new Benchmark.Suite(); | ||
|
||
// Benchmarking | ||
suite.add('got - promise', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
await got(url, gotOptions); | ||
deferred.resolve(); | ||
} | ||
}).add('got - stream', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
got.stream(url, gotOptions).resume().once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('got - promise core', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const stream = new PromisableRequest(url, gotOptions); | ||
stream.resume().once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('got - stream core', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const stream = new Request(url, gotOptions); | ||
stream.resume().once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('got - stream core - normalized options', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const stream = new Request(undefined as any, normalizedGotOptions); | ||
stream.resume().once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('request - callback', { | ||
defer: true, | ||
fn: (deferred: {resolve(): void}) => { | ||
request(urlString, requestOptions, (error: Error) => { | ||
if (error) { | ||
throw error; | ||
} | ||
|
||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('request - stream', { | ||
defer: true, | ||
fn: (deferred: {resolve(): void}) => { | ||
const stream = request(urlString, requestOptions); | ||
stream.resume(); | ||
stream.once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('node-fetch - promise', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const response = await fetch(url, fetchOptions); | ||
await response.text(); | ||
|
||
deferred.resolve(); | ||
} | ||
}).add('node-fetch - stream', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const {body} = await fetch(url, fetchOptions); | ||
|
||
body.resume(); | ||
body.once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('axios - promise', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
await axios.request(axiosOptions); | ||
deferred.resolve(); | ||
} | ||
}).add('axios - stream', { | ||
defer: true, | ||
fn: async (deferred: {resolve(): void}) => { | ||
const {data} = await axios.request(axiosStreamOptions); | ||
data.resume(); | ||
data.once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
} | ||
}).add('https - stream', { | ||
defer: true, | ||
fn: (deferred: {resolve(): void}) => { | ||
https.request(urlString, httpsOptions, response => { | ||
response.resume(); | ||
response.once('end', () => { | ||
deferred.resolve(); | ||
}); | ||
}).end(); | ||
} | ||
}).on('cycle', (event: Benchmark.Event) => { | ||
console.log(String(event.target)); | ||
}).on('complete', function (this: any) { | ||
console.log(`Fastest is ${this.filter('fastest').map('name') as string}`); | ||
|
||
internalBenchmark(); | ||
}).run(); | ||
|
||
const internalBenchmark = (): void => { | ||
console.log(); | ||
|
||
const internalSuite = new Benchmark.Suite(); | ||
internalSuite.add('got - normalize options', { | ||
fn: () => { | ||
normalizeArguments(url, gotOptions); | ||
} | ||
}).on('cycle', (event: Benchmark.Event) => { | ||
console.log(String(event.target)); | ||
}); | ||
|
||
internalSuite.run(); | ||
}; | ||
|
||
// Results (i7-7700k, CPU governor: performance): | ||
// got - promise x 3,092 ops/sec ±5.25% (73 runs sampled) | ||
// got - stream x 4,313 ops/sec ±5.61% (72 runs sampled) | ||
// got - promise core x 6,756 ops/sec ±5.32% (80 runs sampled) | ||
// got - stream core x 6,863 ops/sec ±4.68% (76 runs sampled) | ||
// got - stream core - normalized options x 7,960 ops/sec ±3.83% (81 runs sampled) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalizing cuts out ~1k req/s but the time is needed to duplicate the options, so the original ones won't be altered if you use hooks to modify the request. Hooks are our main adventage while being compared to other HTTP clients. |
||
// request - callback x 6,912 ops/sec ±6.50% (76 runs sampled) | ||
// request - stream x 7,821 ops/sec ±4.28% (80 runs sampled) | ||
// node-fetch - promise x 7,036 ops/sec ±8.17% (78 runs sampled) | ||
// node-fetch - stream x 7,877 ops/sec ±4.17% (80 runs sampled) | ||
// axios - promise x 6,613 ops/sec ±3.22% (76 runs sampled) | ||
// axios - stream x 8,642 ops/sec ±2.84% (79 runs sampled) | ||
// https - stream x 9,955 ops/sec ±6.36% (76 runs sampled) | ||
// Fastest is https - stream | ||
|
||
// got - normalize options x 166,389 ops/sec ±0.63% (91 runs sampled) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {AddressInfo} from 'net'; | ||
import https = require('https'); | ||
// @ts-ignore No types | ||
import createCert = require('create-cert'); | ||
|
||
(async () => { | ||
const keys = await createCert({days: 365, commonName: 'localhost'}); | ||
|
||
const server = https.createServer(keys, (_request, response) => { | ||
response.end('ok'); | ||
}).listen(8080, () => { | ||
const {port} = server.address() as AddressInfo; | ||
|
||
console.log(`Listening at https://localhost:${port}`); | ||
}); | ||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,10 @@ | |
"funding": "https://github.com/sindresorhus/got?sponsor=1", | ||
"main": "dist/source", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=10.19.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @szmarczak Sorry to be commenting on a merged PR, but is there a reason you had to bump this? This should probably be mentioned as a breaking change? |
||
}, | ||
"scripts": { | ||
"test": "xo && tsc --noEmit && nyc ava", | ||
"test": "xo && tsc --noEmit && nyc --reporter=html --reporter=text ava", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very useful to debug later. Generates both HTML output and text output as usual. |
||
"release": "np", | ||
"build": "del-cli dist && tsc", | ||
"prepare": "npm run build" | ||
|
@@ -33,71 +33,68 @@ | |
"fetch", | ||
"net", | ||
"network", | ||
"electron", | ||
"gzip", | ||
"brotli", | ||
"requests", | ||
"human-friendly", | ||
"axios", | ||
"superagent" | ||
"superagent", | ||
"node-fetch", | ||
"ky" | ||
], | ||
"dependencies": { | ||
"@sindresorhus/is": "^2.0.0", | ||
"@sindresorhus/is": "^2.1.0", | ||
"@szmarczak/http-timer": "^4.0.0", | ||
"@types/cacheable-request": "^6.0.1", | ||
"@types/keyv": "3.1.1", | ||
"@types/responselike": "1.0.0", | ||
"cacheable-lookup": "^2.0.0", | ||
"@types/responselike": "^1.0.0", | ||
"cacheable-lookup": "^4.1.1", | ||
"cacheable-request": "^7.0.1", | ||
"decompress-response": "^5.0.0", | ||
"duplexer3": "^0.1.4", | ||
"get-stream": "^5.0.0", | ||
"http2-wrapper": "^1.0.0-beta.4.3", | ||
"lowercase-keys": "^2.0.0", | ||
"mimic-response": "^2.1.0", | ||
"p-cancelable": "^2.0.0", | ||
"p-event": "^4.0.0", | ||
"responselike": "^2.0.0", | ||
"to-readable-stream": "^2.0.0", | ||
"type-fest": "^0.10.0" | ||
"responselike": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@ava/typescript": "^1.1.1", | ||
"@sindresorhus/tsconfig": "^0.7.0", | ||
"@types/duplexer3": "^0.1.0", | ||
"@types/benchmark": "^1.0.31", | ||
"@types/express": "^4.17.2", | ||
"@types/lolex": "^5.1.0", | ||
"@types/node": "13.1.2", | ||
"@types/proxyquire": "^1.3.28", | ||
"@types/node-fetch": "^2.5.5", | ||
"@types/request": "^2.48.4", | ||
"@types/sinon": "^7.0.13", | ||
"@types/tough-cookie": "^2.3.5", | ||
"@typescript-eslint/eslint-plugin": "^2.19.2", | ||
"@typescript-eslint/parser": "^2.19.2", | ||
"ava": "^3.3.0", | ||
"axios": "^0.19.2", | ||
"benchmark": "^2.1.4", | ||
"coveralls": "^3.0.4", | ||
"create-test-server": "^3.0.1", | ||
"del-cli": "^3.0.0", | ||
"delay": "^4.3.0", | ||
"eslint-config-xo-typescript": "^0.26.0", | ||
"express": "^4.17.1", | ||
"form-data": "^3.0.0", | ||
"get-port": "^5.0.0", | ||
"keyv": "^4.0.0", | ||
"lolex": "^6.0.0", | ||
"nock": "^12.0.0", | ||
"node-fetch": "^2.6.0", | ||
"np": "^6.0.0", | ||
"nyc": "^15.0.0", | ||
"proxyquire": "^2.0.1", | ||
"p-event": "^4.0.0", | ||
"sinon": "^8.1.1", | ||
"slow-stream": "0.0.4", | ||
"tempy": "^0.4.0", | ||
"to-readable-stream": "^2.1.0", | ||
"tough-cookie": "^3.0.0", | ||
"typescript": "3.7.5", | ||
"xo": "^0.26.0" | ||
"xo": "^0.26.1" | ||
}, | ||
"types": "dist/source", | ||
"sideEffects": false, | ||
"browser": { | ||
"electron": false | ||
}, | ||
"ava": { | ||
"files": [ | ||
"test/*" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why, but the
got
function cuts out 3k-4k req/s.