Skip to content

Instantly share code, notes, and snippets.

@sam-github

sam-github/index.html Secret

Last active Oct 6, 2018
Embed
What would you like to do?
talk-pitfalls - open index.html with a browser
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<meta charset="utf-8">
<style>
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body { font-family: 'Droid Serif'; }
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: normal;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
@media print {
.remark-slide-number {
/* hide slide numbers on print/PDF, viewer has its own */
display: none;
}
}
@page {
size: 16cm 12cm;
}
</style>
</head>
<body>
<textarea id="source">
class: center, middle
# Title: Node.js API Pitfalls
Who am I:
NodeOps Team Lead at StrongLoop@IBM
github: @sam-github
twitter: @octetcloud
instagram: ... sorry, no!
???
rmg feedback:
- nextTick, don't mention max queue depth
- async.while, use next tick to block the event loop?
jordan feedback:
- make sure I know the slides back and forwards, it will make me confident, so do lots of prep
- be high-energy, be passionate, it improves the energy of the talk
- no intro, just dive in and go
---
# Disclaimer ;-)
Doesn't necessarily reflect the views of Strongloop, IBM, or any of my Node.js
collaborators...
---
# nextTick
```javascript
process.nextTick(function A() {
// Called ...
});
```
- [ ] in next tick of the event loop
- [ ] immediately after current stack returns
---
# nextTick
```javascript
process.nextTick(function A() {
// Called ...
});
```
- [ ] in next tick of the event loop
- [x] immediately after current stack returns
---
# setImmediate
```javascript
setImmediate(function A() {
// Called ...
});
```
- [ ] in next tick of the event loop
- [ ] immediately after current stack returns
---
# setImmediate
```javascript
setImmediate(function A() {
// Called ...
});
```
- [x] in next tick of the event loop
- [ ] immediately after current stack returns
---
# nextTick vs setImmediate
- `nextTick`: adds callback to queue to be called *immediately*
- `setImmediate`: adds callback to queue to be called *next tick*
---
# worker.kill()
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGHUP');
})
.on('exit', function() {
console.log('Exit');
});
} else {
process.on('SIGHUP', function() {
console.log('Hup');
});
}
```
???
Walk through
---
# worker.kill()
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGHUP');
})
.on('exit', function() { console.log('Exit'); });
} else {
process.on('SIGHUP', function() { console.log('Hup'); });
}
```
- [ ] "Hup"
- [ ] "Exit"
- [ ] "Hup" and "Exit"
- [ ] No output
---
# worker.kill()
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGHUP');
})
.on('exit', function() { console.log('Exit'); });
} else {
process.on('SIGHUP', function() { console.log('Hup'); });
}
```
- [ ] "Hup"
- [x] "Exit"
- [ ] "Hup" and "Exit"
- [ ] No output
---
# worker.kill() - what is it really?
```javascript
Worker.prototype.kill = function(signo) {
var proc = this.process;
this.once('disconnect', function() {
this.process.kill(signo || 'SIGTERM');
});
this.disconnect();
};
```
- Use `worker.process.kill()` if you want to signal the worker
- Asymetric with `worker.send()`, `worker.on('message', ...)`, etc.
---
# worker.suicide - kill the worker
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGTERM');
})
.on('exit', function() {
// this.suicide is ....
});
} else {
}
```
- [ ] true
- [ ] false
---
# worker.suicide - kill the worker
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGTERM');
})
.on('exit', function() {
// this.suicide is ....
});
} else {
}
```
- [x] true
- [ ] false
---
# worker.suicide - exit the worker
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('exit', function() {
// this.suicide is ....
});
} else {
process.exit(0);
}
```
- [ ] true
- [ ] false
---
# worker.suicide - exit the worker
```javascript
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('exit', function() {
// this.suicide is ....
});
} else {
process.exit(0);
}
```
- [ ] true
- [x] false
---
# worker.suicide - what does it mean?
Actual meaning: "orderly exit"
- `worker.disconnect()` in parent (implicitly done by `worker.kill()`)
- `process.disconnect()` in worker
???
problems with having "suicide" be the "good thing"
---
# url.parse/format
```javascript
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.host = 'ibm.com';
console.log(url.format(uri));
```
Prints <http://ibm.com:8080/path> ...
- [ ] yes
- [ ] no
---
# url.parse/format
```javascript
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.host = 'ibm.com';
console.log(url.format(uri));
```
Prints <http://ibm.com:8080/path> ...
- [ ] yes
- [x] no: <http://ibm.com/path>
---
# url.parse/format
- `host` is "example.com:8080"
- `hostname` is "example.com"
---
# url.parse/format
```javascript
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.hostname = 'ibm.com';
console.log(url.format(uri));
```
Prints <http://ibm.com:8080/path> ...
- [ ] yes
- [ ] no
---
# url.parse/format
```javascript
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.hostname = 'ibm.com';
console.log(url.format(uri));
```
Prints <http://ibm.com:8080/path> ...
- [ ] yes
- [x] no: <http://example.com:8080/path>
---
# url.parse/format
- `hostname` and `port` are ignored if `host` is present...
---
# url.parse/format
```javascript
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
delete uri.host;
uri.hostname = 'ibm.com';
console.log(url.format(uri));
```
- <http://ibm.com:8080/path>, finally!
---
# url.parse/format
- parse: "http://example:8080":
- `port` is 8080
- `host` is "example:8080"... why not `hostport`?
- `hostname` is "example"... why not `host`?
- format: `hostname` and `port` are ignored if `host` is present
- shouldn't they be prefered over `host` if present?
---
# path.parse/format
```javascript
var path = require('path');
var bits = path.parse('some/dir/index.txt');
// has: .name, .ext
bits.ext = '.html';
console.log(path.format(bits));
```
Logs `some/dir/index.html`...
- [ ] yes
- [ ] no
---
# path.parse/format
```javascript
var path = require('path');
var bits = path.parse('some/dir/index.txt');
bits.ext = '.html';
console.log(path.format(bits));
```
Logs `some/dir/index.html`...
- [ ] yes
- [x] no: `some/dir/index.txt`
---
# path.parse/format
Its probably like `url`...
```javascript
var path = require('path');
var bits = path.parse('some/dir/index.txt');
console.log(bits.base); // > index.txt
delete bits.base
bits.ext = '.html';
console.log(path.format(bits));
```
Logs `some/dir/index.html`...
- [ ] yes
- [ ] no
---
# path.parse/format
```javascript
var path = require('path');
var bits = path.parse('some/dir/index.txt');
console.log(bits.base); // > index.txt
delete bits.base
bits.ext = '.html';
console.log(path.format(bits));
```
Logs `some/dir/index.html`...
- [ ] yes
- [x] no: `some/dir/`
---
# path.parse/format
Its just completely different, format _always_ ignores `name` and `ext`.
Correct:
```javascript
var path = require('path');
var bits = path.parse('some/dir/index.txt');
bits.base = bits.name + '.html';
console.log(path.format(bits)); // > some/dir/index.html
```
---
# streams v1, 2, 3
From <https://nodejs.org/api/stream.html#stream_class_stream_readable>:
> Note that, for backwards compatibility reasons, removing 'data' event
handlers will not automatically pause the stream. Also, if there are piped
destinations, then calling pause() will not guarantee that the stream will
remain paused once those destinations drain and ask for more data.
---
# streams v1, 2, 3
From <https://nodejs.org/api/stream.html#stream_class_stream_readable>:
> Note that, for backwards compatibility reasons, removing 'data' event
handlers will not automatically pause the stream. Also, if there are piped
destinations, then calling pause() will not guarantee that the stream will
remain paused once those destinations drain and ask for more data.
_When can we delete backwards compat to v0.8?_
---
# Question
What kind of node do you want: a good one? or a (mostly) v0.8 compatible one?
@octetcloud As of right now, 30.4% of registered npm accounts are less
than 6 months old.
- Laurie Voss (@seldo), NPM, Nov. 28, 2015
---
# Answer
Its yours (and a lot of other people's) Node.js, speak out:
- github, twitter, etc..
- Be tolerant (or intolerant) of breakages, but what you say will effect
what happens.
---
# Feedback:
- github: @sam-github
- twitter: @octetcloud
- talk source: <https://gist.github.com/sam-github/4c5c019b92cf95fb6571>,
or <https://goo.gl/2RWpqE>
</textarea>
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
</script>
<script>
var slideshow = remark.create();
</script>
</body>
</html>
process.nextTick(function A() {
process.nextTick(function B() {
// Called in next tick, or immediately after A returns?
});
});
// Called immediately
var path = require('path');
var bits = path.parse('some/dir/index.txt');
bits.ext = '.html';
console.log(path.format(bits)); // some/dir/index.txt
var path = require('path');
var bits = path.parse('some/dir/index.txt');
console.log(bits.base); // index.txt
delete bits.base
bits.ext = '.html';
console.log(path.format(bits)); // some/dir/
var path = require('path');
var bits = path.parse('some/dir/index.txt');
bits.base = bits.name + '.html';
console.log(path.format(bits)); // some/dir/index.html
setImmediate(function A() {
setImmediate(function B() {
// Called in next tick, or immediately after A returns?
});
});
// Called in the next tick
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = '<34>Oct 11 22:14:15 mymachine';
//sock.send(mesg, 514, 'localhost');
// TypeError: First argument must be a buffer object.
// No other network APIs require Buffers (to my knowledge)
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = Buffer('<34>Oct 11 22:14:15 mymachine');
//sock.send(mesg, 514, 'localhost');
// RangeError: Offset into buffer too large
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = Buffer('<34>Oct 11 22:14:15 mymachine');
sock.send(mesg, 0, mesg.length, 514, 'localhost');
// yeah!
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.host = 'ibm.com';
console.log(url.format(uri));
// replaces the host and port
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
uri.hostname = 'ibm.com';
console.log(url.format(uri));
// replaces nothing
var url = require('url');
var uri = url.parse('http://example.com:8080/path');
delete uri.host;
uri.hostname = 'ibm.com';
console.log(url.format(uri));
// worked
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGHUP');
})
.on('exit', function(code, signame) {
console.log('Exit');
});
} else {
process.on('SIGHUP', function() {
console.log('Hup');
});
}
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGHUP');
})
.on('exit', function(code, signame) {
// FIXME why does it say it exited with SIGHUP? This is uv cacheing the
// signo, right? strace this
console.log('Exit with:', signame || code);
});
} else {
process.on('SIGHUP', function() {
console.log('Hup, hup!');
});
}
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('online', function() {
this.kill('SIGTERM');
})
.on('exit', function(code, signame) {
console.log('Exit with:', signame || code);
console.log('Suicide?', this.suicide);
});
} else {
}
var cluster = require('cluster');
if (cluster.isMaster) {
cluster.fork()
.on('exit', function(code, signame) {
console.log('Exit with:', signame || code);
console.log('Suicide?', this.suicide);
});
} else {
process.exit(0);
}
# dgram.send()
```javascript
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = '<34>Oct 11 22:14:15 mymachine.samtu.com got lost in the cloud';
sock.send(mesg, 514, 'localhost');
```
Look OK?
---
# dgram.send()
```javascript
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = '<34>Oct 11 22:14:15 mymachine.samtu.com got lost in the cloud';
sock.send(mesg, 514, 'localhost');
// > TypeError: First argument must be a buffer object.
```
No other network APIs _require_ Buffers (to my knowledge)
---
# dgram.send()
```javascript
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = Buffer('<34>Oct 11 22:14:15 mymachine.samtu.com got lost in the cloud');
sock.send(mesg, 514, 'localhost');
```
Look OK now?
---
# dgram.send()
```javascript
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = Buffer('<34>Oct 11 22:14:15 mymachine.samtu.com got lost in the cloud');
sock.send(mesg, 514, 'localhost');
// > RangeError: Offset into buffer too large
```
`dgram` has no defaults... have to specify everything!
---
# dgram.send()
Correct:
```javascript
var dgram = require('dgram');
var sock = dgram.createSocket('udp4');
var mesg = Buffer('<34>Oct 11 22:14:15 mymachine.samtu.com got lost in the cloud');
sock.send(mesg, 0, mesg.length, 514, 'localhost');
```
???
Documented... but idiosyncratic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment