- Assertion testing
- Async hooks
- Buffer
- C++ Addons
- C/C++ Addons with N-API
- C++ Embedder API
- Child Processes
- Cluster
- Command line options
- Console
- Crypto
- Debugger
- Deprecated APIs
- DNS
- Domain
- Errors
- Events
- File system
- Globals
- HTTP
- HTTP/2
- HTTPS
- Inspector
- Internationalization
- Modules: CommonJS modules
- Modules: ECMAScript modules
- Modules:
module
API - Modules: Packages
- Net
- OS
- Path
- Performance hooks
- Policies
- Process
- Punycode
- Query strings
- Readline
- REPL
- Report
- Stream
- String decoder
- Timers
- TLS/SSL
- Trace events
- TTY
- UDP/datagram
- URL
- Utilities
- V8
- VM
- WASI
- Worker threads
- Zlib
Node.js v12.22.2 Documentation
Table of Contents
- About this documentation
- Usage and example
- Assert
- Strict assertion mode
- Legacy assertion mode
- Class: assert.AssertionError
- Class:
assert.CallTracker
assert(value[, message])
assert.deepEqual(actual, expected[, message])
assert.deepStrictEqual(actual, expected[, message])
assert.doesNotMatch(string, regexp[, message])
assert.doesNotReject(asyncFn[, error][, message])
assert.doesNotThrow(fn[, error][, message])
assert.equal(actual, expected[, message])
assert.fail([message])
assert.fail(actual, expected[, message[, operator[, stackStartFn]]])
assert.ifError(value)
assert.match(string, regexp[, message])
assert.notDeepEqual(actual, expected[, message])
assert.notDeepStrictEqual(actual, expected[, message])
assert.notEqual(actual, expected[, message])
assert.notStrictEqual(actual, expected[, message])
assert.ok(value[, message])
assert.rejects(asyncFn[, error][, message])
assert.strictEqual(actual, expected[, message])
assert.throws(fn[, error][, message])
- Async hooks
- Terminology
- Public API
- Promise execution tracking
- JavaScript embedder API
- Class:
AsyncLocalStorage
- Buffer
- Buffers and character encodings
- Buffers and TypedArrays
- Buffers and iteration
- Class:
Buffer
- Static method:
Buffer.alloc(size[, fill[, encoding]])
- Static method:
Buffer.allocUnsafe(size)
- Static method:
Buffer.allocUnsafeSlow(size)
- Static method:
Buffer.byteLength(string[, encoding])
- Static method:
Buffer.compare(buf1, buf2)
- Static method:
Buffer.concat(list[, totalLength])
- Static method:
Buffer.from(array)
- Static method:
Buffer.from(arrayBuffer[, byteOffset[, length]])
- Static method:
Buffer.from(buffer)
- Static method:
Buffer.from(object[, offsetOrEncoding[, length]])
- Static method:
Buffer.from(string[, encoding])
- Static method:
Buffer.isBuffer(obj)
- Static method:
Buffer.isEncoding(encoding)
- Class property:
Buffer.poolSize
buf[index]
buf.buffer
buf.byteOffset
buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
buf.entries()
buf.equals(otherBuffer)
buf.fill(value[, offset[, end]][, encoding])
buf.includes(value[, byteOffset][, encoding])
buf.indexOf(value[, byteOffset][, encoding])
buf.keys()
buf.lastIndexOf(value[, byteOffset][, encoding])
buf.length
buf.parent
buf.readBigInt64BE([offset])
buf.readBigInt64LE([offset])
buf.readBigUInt64BE([offset])
buf.readBigUInt64LE([offset])
buf.readDoubleBE([offset])
buf.readDoubleLE([offset])
buf.readFloatBE([offset])
buf.readFloatLE([offset])
buf.readInt8([offset])
buf.readInt16BE([offset])
buf.readInt16LE([offset])
buf.readInt32BE([offset])
buf.readInt32LE([offset])
buf.readIntBE(offset, byteLength)
buf.readIntLE(offset, byteLength)
buf.readUInt8([offset])
buf.readUInt16BE([offset])
buf.readUInt16LE([offset])
buf.readUInt32BE([offset])
buf.readUInt32LE([offset])
buf.readUIntBE(offset, byteLength)
buf.readUIntLE(offset, byteLength)
buf.subarray([start[, end]])
buf.slice([start[, end]])
buf.swap16()
buf.swap32()
buf.swap64()
buf.toJSON()
buf.toString([encoding[, start[, end]]])
buf.values()
buf.write(string[, offset[, length]][, encoding])
buf.writeBigInt64BE(value[, offset])
buf.writeBigInt64LE(value[, offset])
buf.writeBigUInt64BE(value[, offset])
buf.writeBigUInt64LE(value[, offset])
buf.writeDoubleBE(value[, offset])
buf.writeDoubleLE(value[, offset])
buf.writeFloatBE(value[, offset])
buf.writeFloatLE(value[, offset])
buf.writeInt8(value[, offset])
buf.writeInt16BE(value[, offset])
buf.writeInt16LE(value[, offset])
buf.writeInt32BE(value[, offset])
buf.writeInt32LE(value[, offset])
buf.writeIntBE(value, offset, byteLength)
buf.writeIntLE(value, offset, byteLength)
buf.writeUInt8(value[, offset])
buf.writeUInt16BE(value[, offset])
buf.writeUInt16LE(value[, offset])
buf.writeUInt32BE(value[, offset])
buf.writeUInt32LE(value[, offset])
buf.writeUIntBE(value, offset, byteLength)
buf.writeUIntLE(value, offset, byteLength)
new Buffer(array)
new Buffer(arrayBuffer[, byteOffset[, length]])
new Buffer(buffer)
new Buffer(size)
new Buffer(string[, encoding])
- Static method:
buffer
module APIsBuffer.from()
,Buffer.alloc()
, andBuffer.allocUnsafe()
- C++ addons
- N-API
- Implications of ABI stability
- Building
- Usage
- N-API version matrix
- Environment life cycle APIs
- Basic N-API data types
- Error handling
- Object lifetime management
- Module registration
- Working with JavaScript values
- Enum types
- Object creation functions
- Functions to convert from C types to N-API
- Functions to convert from N-API to C types
- napi_get_array_length
- napi_get_arraybuffer_info
- napi_get_buffer_info
- napi_get_prototype
- napi_get_typedarray_info
- napi_get_dataview_info
- napi_get_date_value
- napi_get_value_bool
- napi_get_value_double
- napi_get_value_bigint_int64
- napi_get_value_bigint_uint64
- napi_get_value_bigint_words
- napi_get_value_external
- napi_get_value_int32
- napi_get_value_int64
- napi_get_value_string_latin1
- napi_get_value_string_utf8
- napi_get_value_string_utf16
- napi_get_value_uint32
- Functions to get global instances
- Working with JavaScript values and abstract operations
- Working with JavaScript properties
- Structures
- Functions
- napi_get_property_names
- napi_get_all_property_names
- napi_set_property
- napi_get_property
- napi_has_property
- napi_delete_property
- napi_has_own_property
- napi_set_named_property
- napi_get_named_property
- napi_has_named_property
- napi_set_element
- napi_get_element
- napi_has_element
- napi_delete_element
- napi_define_properties
- napi_object_freeze
- napi_object_seal
- Working with JavaScript functions
- Object wrap
- Simple asynchronous operations
- Custom asynchronous operations
- Version management
- Memory management
- Promises
- Script execution
- libuv event loop
- Asynchronous thread-safe function calls
- Calling a thread-safe function
- Reference counting of thread-safe functions
- Deciding whether to keep the process running
- napi_create_threadsafe_function
- napi_get_threadsafe_function_context
- napi_call_threadsafe_function
- napi_acquire_threadsafe_function
- napi_release_threadsafe_function
- napi_ref_threadsafe_function
- napi_unref_threadsafe_function
- Miscellaneous utilities
- node_api_get_module_file_name
- C++ Embedder API
- Child process
- Asynchronous process creation
- Synchronous process creation
- Class:
ChildProcess
- Event:
'close'
- Event:
'disconnect'
- Event:
'error'
- Event:
'exit'
- Event:
'message'
subprocess.channel
subprocess.connected
subprocess.disconnect()
subprocess.exitCode
subprocess.kill([signal])
subprocess.killed
subprocess.pid
subprocess.ref()
subprocess.send(message[, sendHandle[, options]][, callback])
subprocess.signalCode
subprocess.spawnargs
subprocess.spawnfile
subprocess.stderr
subprocess.stdin
subprocess.stdio
subprocess.stdout
subprocess.unref()
- Event:
maxBuffer
and Unicode- Shell requirements
- Default Windows shell
- Advanced serialization
- Cluster
- How it works
- Class:
Worker
- Event:
'disconnect'
- Event:
'exit'
- Event:
'fork'
- Event:
'listening'
- Event:
'message'
- Event:
'online'
- Event:
'setup'
cluster.disconnect([callback])
cluster.fork([env])
cluster.isMaster
cluster.isWorker
cluster.schedulingPolicy
cluster.settings
cluster.setupMaster([settings])
cluster.worker
cluster.workers
- Command line options
- Synopsis
- Options
-
--
--abort-on-uncaught-exception
--completion-bash
--conditions=condition
--cpu-prof
--cpu-prof-dir
--cpu-prof-interval
--cpu-prof-name
--diagnostic-dir=directory
--disable-proto=mode
--disallow-code-generation-from-strings
--enable-fips
--enable-source-maps
--experimental-import-meta-resolve
--experimental-json-modules
--experimental-loader=module
--experimental-modules
--experimental-policy
--experimental-repl-await
--experimental-specifier-resolution=mode
--experimental-vm-modules
--experimental-wasi-unstable-preview1
--experimental-wasm-modules
--force-context-aware
--force-fips
--frozen-intrinsics
--heapsnapshot-signal=signal
--heap-prof
--heap-prof-dir
--heap-prof-interval
--heap-prof-name
--http-parser=library
--http-server-default-timeout=milliseconds
--icu-data-dir=file
--input-type=type
--inspect-brk[=[host:]port]
--inspect-port=[host:]port
--inspect[=[host:]port]
--inspect-publish-uid=stderr,http
--insecure-http-parser
--jitless
--max-http-header-size=size
--napi-modules
--no-deprecation
--no-force-async-hooks-checks
--no-warnings
--openssl-config=file
--pending-deprecation
--policy-integrity=sri
--preserve-symlinks
--preserve-symlinks-main
--prof
--prof-process
--redirect-warnings=file
--report-compact
--report-dir=directory
,report-directory=directory
--report-filename=filename
--report-on-fatalerror
--report-on-signal
--report-signal=signal
--report-uncaught-exception
--throw-deprecation
--title=title
--tls-cipher-list=list
--tls-keylog=file
--tls-max-v1.2
--tls-max-v1.3
--tls-min-v1.0
--tls-min-v1.1
--tls-min-v1.2
--tls-min-v1.3
--trace-deprecation
--trace-event-categories
--trace-event-file-pattern
--trace-events-enabled
--trace-exit
--trace-sigint
--trace-sync-io
--trace-tls
--trace-uncaught
--trace-warnings
--track-heap-objects
--unhandled-rejections=mode
--use-bundled-ca
,--use-openssl-ca
--use-largepages=mode
--v8-options
--v8-pool-size=num
--zero-fill-buffers
-c
,--check
-e
,--eval "script"
-h
,--help
-i
,--interactive
-p
,--print "script"
-r
,--require module
-v
,--version
- Environment variables
NODE_DEBUG=module[,…]
NODE_DEBUG_NATIVE=module[,…]
NODE_DISABLE_COLORS=1
NODE_EXTRA_CA_CERTS=file
NODE_ICU_DATA=file
NODE_NO_WARNINGS=1
NODE_OPTIONS=options...
NODE_PATH=path[:…]
NODE_PENDING_DEPRECATION=1
NODE_PENDING_PIPE_INSTANCES=instances
NODE_PRESERVE_SYMLINKS=1
NODE_REDIRECT_WARNINGS=file
NODE_REPL_HISTORY=file
NODE_REPL_EXTERNAL_MODULE=file
NODE_TLS_REJECT_UNAUTHORIZED=value
NODE_V8_COVERAGE=dir
OPENSSL_CONF=file
SSL_CERT_DIR=dir
SSL_CERT_FILE=file
UV_THREADPOOL_SIZE=size
- Useful V8 options
- Console
- Class:
Console
new Console(stdout[, stderr][, ignoreErrors])
new Console(options)
console.assert(value[, ...message])
console.clear()
console.count([label])
console.countReset([label])
console.debug(data[, ...args])
console.dir(obj[, options])
console.dirxml(...data)
console.error([data][, ...args])
console.group([...label])
console.groupCollapsed()
console.groupEnd()
console.info([data][, ...args])
console.log([data][, ...args])
console.table(tabularData[, properties])
console.time([label])
console.timeEnd([label])
console.timeLog([label][, ...data])
console.trace([message][, ...args])
console.warn([data][, ...args])
- Inspector only methods
- Class:
- Crypto
- Determining if crypto support is unavailable
- Class:
Certificate
- Class:
Cipher
- Class:
Decipher
- Class:
DiffieHellman
diffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])
diffieHellman.generateKeys([encoding])
diffieHellman.getGenerator([encoding])
diffieHellman.getPrime([encoding])
diffieHellman.getPrivateKey([encoding])
diffieHellman.getPublicKey([encoding])
diffieHellman.setPrivateKey(privateKey[, encoding])
diffieHellman.setPublicKey(publicKey[, encoding])
diffieHellman.verifyError
- Class:
DiffieHellmanGroup
- Class:
ECDH
- Static method:
ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])
ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])
ecdh.generateKeys([encoding[, format]])
ecdh.getPrivateKey([encoding])
ecdh.getPublicKey([encoding][, format])
ecdh.setPrivateKey(privateKey[, encoding])
ecdh.setPublicKey(publicKey[, encoding])
- Static method:
- Class:
Hash
- Class:
Hmac
- Class:
KeyObject
- Class:
Sign
- Class:
Verify
crypto
module methods and propertiescrypto.constants
crypto.DEFAULT_ENCODING
crypto.fips
crypto.createCipher(algorithm, password[, options])
crypto.createCipheriv(algorithm, key, iv[, options])
crypto.createDecipher(algorithm, password[, options])
crypto.createDecipheriv(algorithm, key, iv[, options])
crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])
crypto.createDiffieHellman(primeLength[, generator])
crypto.createDiffieHellmanGroup(name)
crypto.createECDH(curveName)
crypto.createHash(algorithm[, options])
crypto.createHmac(algorithm, key[, options])
crypto.createPrivateKey(key)
crypto.createPublicKey(key)
crypto.createSecretKey(key)
crypto.createSign(algorithm[, options])
crypto.createVerify(algorithm[, options])
crypto.diffieHellman(options)
crypto.generateKeyPair(type, options, callback)
crypto.generateKeyPairSync(type, options)
crypto.getCiphers()
crypto.getCurves()
crypto.getDiffieHellman(groupName)
crypto.getFips()
crypto.getHashes()
crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)
crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)
crypto.privateDecrypt(privateKey, buffer)
crypto.privateEncrypt(privateKey, buffer)
crypto.publicDecrypt(key, buffer)
crypto.publicEncrypt(key, buffer)
crypto.randomBytes(size[, callback])
crypto.randomFillSync(buffer[, offset][, size])
crypto.randomFill(buffer[, offset][, size], callback)
crypto.randomInt([min, ]max[, callback])
crypto.scrypt(password, salt, keylen[, options], callback)
crypto.scryptSync(password, salt, keylen[, options])
crypto.setEngine(engine[, flags])
crypto.setFips(bool)
crypto.sign(algorithm, data, key)
crypto.timingSafeEqual(a, b)
crypto.verify(algorithm, data, key, signature)
- Notes
- Crypto constants
- Debugger
- Deprecated APIs
- Revoking deprecations
- List of deprecated APIs
- DEP0001:
http.OutgoingMessage.prototype.flush
- DEP0002:
require('_linklist')
- DEP0003:
_writableState.buffer
- DEP0004:
CryptoStream.prototype.readyState
- DEP0005:
Buffer()
constructor - DEP0006:
child_process
options.customFds
- DEP0007: Replace
cluster
worker.suicide
withworker.exitedAfterDisconnect
- DEP0008:
require('constants')
- DEP0009:
crypto.pbkdf2
without digest - DEP0010:
crypto.createCredentials
- DEP0011:
crypto.Credentials
- DEP0012:
Domain.dispose
- DEP0013:
fs
asynchronous function without callback - DEP0014:
fs.read
legacy String interface - DEP0015:
fs.readSync
legacy String interface - DEP0016:
GLOBAL
/root
- DEP0017:
Intl.v8BreakIterator
- DEP0018: Unhandled promise rejections
- DEP0019:
require('.')
resolved outside directory - DEP0020:
Server.connections
- DEP0021:
Server.listenFD
- DEP0022:
os.tmpDir()
- DEP0023:
os.getNetworkInterfaces()
- DEP0024:
REPLServer.prototype.convertToContext()
- DEP0025:
require('sys')
- DEP0026:
util.print()
- DEP0027:
util.puts()
- DEP0028:
util.debug()
- DEP0029:
util.error()
- DEP0030:
SlowBuffer
- DEP0031:
ecdh.setPublicKey()
- DEP0032:
domain
module - DEP0033:
EventEmitter.listenerCount()
- DEP0034:
fs.exists(path, callback)
- DEP0035:
fs.lchmod(path, mode, callback)
- DEP0036:
fs.lchmodSync(path, mode)
- DEP0037:
fs.lchown(path, uid, gid, callback)
- DEP0038:
fs.lchownSync(path, uid, gid)
- DEP0039:
require.extensions
- DEP0040:
punycode
module - DEP0041:
NODE_REPL_HISTORY_FILE
environment variable - DEP0042:
tls.CryptoStream
- DEP0043:
tls.SecurePair
- DEP0044:
util.isArray()
- DEP0045:
util.isBoolean()
- DEP0046:
util.isBuffer()
- DEP0047:
util.isDate()
- DEP0048:
util.isError()
- DEP0049:
util.isFunction()
- DEP0050:
util.isNull()
- DEP0051:
util.isNullOrUndefined()
- DEP0052:
util.isNumber()
- DEP0053
util.isObject()
- DEP0054:
util.isPrimitive()
- DEP0055:
util.isRegExp()
- DEP0056:
util.isString()
- DEP0057:
util.isSymbol()
- DEP0058:
util.isUndefined()
- DEP0059:
util.log()
- DEP0060:
util._extend()
- DEP0061:
fs.SyncWriteStream
- DEP0062:
node --debug
- DEP0063:
ServerResponse.prototype.writeHeader()
- DEP0064:
tls.createSecurePair()
- DEP0065:
repl.REPL_MODE_MAGIC
andNODE_REPL_MODE=magic
- DEP0066:
OutgoingMessage.prototype._headers, OutgoingMessage.prototype._headerNames
- DEP0067:
OutgoingMessage.prototype._renderHeaders
- DEP0068:
node debug
- DEP0069:
vm.runInDebugContext(string)
- DEP0070:
async_hooks.currentId()
- DEP0071:
async_hooks.triggerId()
- DEP0072:
async_hooks.AsyncResource.triggerId()
- DEP0073: Several internal properties of
net.Server
- DEP0074:
REPLServer.bufferedCommand
- DEP0075:
REPLServer.parseREPLKeyword()
- DEP0076:
tls.parseCertString()
- DEP0077:
Module._debug()
- DEP0078:
REPLServer.turnOffEditorMode()
- DEP0079: Custom inspection function on objects via
.inspect()
- DEP0080:
path._makeLong()
- DEP0081:
fs.truncate()
using a file descriptor - DEP0082:
REPLServer.prototype.memory()
- DEP0083: Disabling ECDH by setting
ecdhCurve
tofalse
- DEP0084: requiring bundled internal dependencies
- DEP0085: AsyncHooks sensitive API
- DEP0086: Remove
runInAsyncIdScope
- DEP0089:
require('assert')
- DEP0090: Invalid GCM authentication tag lengths
- DEP0091:
crypto.DEFAULT_ENCODING
- DEP0092: Top-level
this
bound tomodule.exports
- DEP0093:
crypto.fips
is deprecated and replaced. - DEP0094: Using
assert.fail()
with more than one argument. - DEP0095:
timers.enroll()
- DEP0096:
timers.unenroll()
- DEP0097:
MakeCallback
withdomain
property - DEP0098: AsyncHooks embedder
AsyncResource.emitBefore
andAsyncResource.emitAfter
APIs - DEP0099: Async context-unaware
node::MakeCallback
C++ APIs - DEP0100:
process.assert()
- DEP0101:
--with-lttng
- DEP0102: Using
noAssert
inBuffer#(read|write)
operations. - DEP0103:
process.binding('util').is[...]
typechecks - DEP0104:
process.env
string coercion - DEP0105:
decipher.finaltol
- DEP0106:
crypto.createCipher
andcrypto.createDecipher
- DEP0107:
tls.convertNPNProtocols()
- DEP0108:
zlib.bytesRead
- DEP0109:
http
,https
, andtls
support for invalid URLs - DEP0110:
vm.Script
cached data - DEP0111:
process.binding()
- DEP0112:
dgram
private APIs - DEP0113:
Cipher.setAuthTag()
,Decipher.getAuthTag()
- DEP0114:
crypto._toBuf()
- DEP0115:
crypto.prng()
,crypto.pseudoRandomBytes()
,crypto.rng()
- DEP0116: Legacy URL API
- DEP0117: Native crypto handles
- DEP0118:
dns.lookup()
support for a falsy host name - DEP0119:
process.binding('uv').errname()
private API - DEP0120: Windows Performance Counter support
- DEP0121:
net._setSimultaneousAccepts()
- DEP0122:
tls
Server.prototype.setOptions()
- DEP0123: setting the TLS ServerName to an IP address
- DEP0124: using
REPLServer.rli
- DEP0125:
require('_stream_wrap')
- DEP0126:
timers.active()
- DEP0127:
timers._unrefActive()
- DEP0128: modules with an invalid
main
entry and anindex.js
file - DEP0129:
ChildProcess._channel
- DEP0130:
Module.createRequireFromPath()
- DEP0131: Legacy HTTP parser
- DEP0132:
worker.terminate()
with callback - DEP0133:
http
connection
- DEP0134:
process._tickCallback
- DEP0136:
http
finished
- DEP0139:
process.umask()
with no arguments - DEP0144:
module.parent
- DEP0001:
- DNS
- Class:
dns.Resolver
dns.getServers()
dns.lookup(hostname[, options], callback)
dns.lookupService(address, port, callback)
dns.resolve(hostname[, rrtype], callback)
dns.resolve4(hostname[, options], callback)
dns.resolve6(hostname[, options], callback)
dns.resolveAny(hostname, callback)
dns.resolveCname(hostname, callback)
dns.resolveMx(hostname, callback)
dns.resolveNaptr(hostname, callback)
dns.resolveNs(hostname, callback)
dns.resolvePtr(hostname, callback)
dns.resolveSoa(hostname, callback)
dns.resolveSrv(hostname, callback)
dns.resolveTxt(hostname, callback)
dns.reverse(ip, callback)
dns.setServers(servers)
- DNS promises API
- Class:
dnsPromises.Resolver
dnsPromises.getServers()
dnsPromises.lookup(hostname[, options])
dnsPromises.lookupService(address, port)
dnsPromises.resolve(hostname[, rrtype])
dnsPromises.resolve4(hostname[, options])
dnsPromises.resolve6(hostname[, options])
dnsPromises.resolveAny(hostname)
dnsPromises.resolveCname(hostname)
dnsPromises.resolveMx(hostname)
dnsPromises.resolveNaptr(hostname)
dnsPromises.resolveNs(hostname)
dnsPromises.resolvePtr(hostname)
dnsPromises.resolveSoa(hostname)
dnsPromises.resolveSrv(hostname)
dnsPromises.resolveTxt(hostname)
dnsPromises.reverse(ip)
dnsPromises.setServers(servers)
- Class:
- Error codes
- Implementation considerations
- Class:
- Domain
- Errors
- Error propagation and interception
- Class:
Error
- Class:
AssertionError
- Class:
RangeError
- Class:
ReferenceError
- Class:
SyntaxError
- Class:
SystemError
- Class:
TypeError
- Exceptions vs. errors
- OpenSSL errors
- Node.js error codes
ERR_AMBIGUOUS_ARGUMENT
ERR_ARG_NOT_ITERABLE
ERR_ASSERTION
ERR_ASYNC_CALLBACK
ERR_ASYNC_TYPE
ERR_BROTLI_COMPRESSION_FAILED
ERR_BROTLI_INVALID_PARAM
ERR_BUFFER_CONTEXT_NOT_AVAILABLE
ERR_BUFFER_OUT_OF_BOUNDS
ERR_BUFFER_TOO_LARGE
ERR_CANNOT_WATCH_SIGINT
ERR_CHILD_CLOSED_BEFORE_REPLY
ERR_CHILD_PROCESS_IPC_REQUIRED
ERR_CHILD_PROCESS_STDIO_MAXBUFFER
ERR_CONSOLE_WRITABLE_STREAM
ERR_CONSTRUCT_CALL_REQUIRED
ERR_CONSTRUCT_CALL_INVALID
ERR_CPU_USAGE
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED
ERR_CRYPTO_ECDH_INVALID_FORMAT
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY
ERR_CRYPTO_ENGINE_UNKNOWN
ERR_CRYPTO_FIPS_FORCED
ERR_CRYPTO_FIPS_UNAVAILABLE
ERR_CRYPTO_HASH_FINALIZED
ERR_CRYPTO_HASH_UPDATE_FAILED
ERR_CRYPTO_INCOMPATIBLE_KEY
ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS
ERR_CRYPTO_INVALID_DIGEST
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE
ERR_CRYPTO_INVALID_STATE
ERR_CRYPTO_PBKDF2_ERROR
ERR_CRYPTO_SCRYPT_INVALID_PARAMETER
ERR_CRYPTO_SCRYPT_NOT_SUPPORTED
ERR_CRYPTO_SIGN_KEY_REQUIRED
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH
ERR_CRYPTO_UNKNOWN_CIPHER
ERR_CRYPTO_UNKNOWN_DH_GROUP
ERR_DIR_CLOSED
ERR_DIR_CONCURRENT_OPERATION
ERR_DNS_SET_SERVERS_FAILED
ERR_DOMAIN_CALLBACK_NOT_AVAILABLE
ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE
ERR_ENCODING_INVALID_ENCODED_DATA
ERR_ENCODING_NOT_SUPPORTED
ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE
ERR_FALSY_VALUE_REJECTION
ERR_FS_FILE_TOO_LARGE
ERR_FS_INVALID_SYMLINK_TYPE
ERR_HTTP_HEADERS_SENT
ERR_HTTP_INVALID_HEADER_VALUE
ERR_HTTP_INVALID_STATUS_CODE
ERR_HTTP_TRAILER_INVALID
ERR_HTTP2_ALTSVC_INVALID_ORIGIN
ERR_HTTP2_ALTSVC_LENGTH
ERR_HTTP2_CONNECT_AUTHORITY
ERR_HTTP2_CONNECT_PATH
ERR_HTTP2_CONNECT_SCHEME
ERR_HTTP2_ERROR
ERR_HTTP2_GOAWAY_SESSION
ERR_HTTP2_HEADERS_AFTER_RESPOND
ERR_HTTP2_HEADERS_SENT
ERR_HTTP2_HEADER_SINGLE_VALUE
ERR_HTTP2_INFO_STATUS_NOT_ALLOWED
ERR_HTTP2_INVALID_CONNECTION_HEADERS
ERR_HTTP2_INVALID_HEADER_VALUE
ERR_HTTP2_INVALID_INFO_STATUS
ERR_HTTP2_INVALID_ORIGIN
ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH
ERR_HTTP2_INVALID_PSEUDOHEADER
ERR_HTTP2_INVALID_SESSION
ERR_HTTP2_INVALID_SETTING_VALUE
ERR_HTTP2_INVALID_STREAM
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK
ERR_HTTP2_NESTED_PUSH
ERR_HTTP2_NO_SOCKET_MANIPULATION
ERR_HTTP2_ORIGIN_LENGTH
ERR_HTTP2_OUT_OF_STREAMS
ERR_HTTP2_PAYLOAD_FORBIDDEN
ERR_HTTP2_PING_CANCEL
ERR_HTTP2_PING_LENGTH
ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED
ERR_HTTP2_PUSH_DISABLED
ERR_HTTP2_SEND_FILE
ERR_HTTP2_SEND_FILE_NOSEEK
ERR_HTTP2_SESSION_ERROR
ERR_HTTP2_SETTINGS_CANCEL
ERR_HTTP2_SOCKET_BOUND
ERR_HTTP2_SOCKET_UNBOUND
ERR_HTTP2_STATUS_101
ERR_HTTP2_STATUS_INVALID
ERR_HTTP2_STREAM_CANCEL
ERR_HTTP2_STREAM_ERROR
ERR_HTTP2_STREAM_SELF_DEPENDENCY
ERR_HTTP2_TRAILERS_ALREADY_SENT
ERR_HTTP2_TRAILERS_NOT_READY
ERR_HTTP2_UNSUPPORTED_PROTOCOL
ERR_INTERNAL_ASSERTION
ERR_INCOMPATIBLE_OPTION_PAIR
ERR_INPUT_TYPE_NOT_ALLOWED
ERR_INSPECTOR_ALREADY_ACTIVATED
ERR_INSPECTOR_ALREADY_CONNECTED
ERR_INSPECTOR_CLOSED
ERR_INSPECTOR_COMMAND
ERR_INSPECTOR_NOT_ACTIVE
ERR_INSPECTOR_NOT_AVAILABLE
ERR_INSPECTOR_NOT_CONNECTED
ERR_INSPECTOR_NOT_WORKER
ERR_INVALID_ADDRESS_FAMILY
ERR_INVALID_ARG_TYPE
ERR_INVALID_ARG_VALUE
ERR_INVALID_ASYNC_ID
ERR_INVALID_BUFFER_SIZE
ERR_INVALID_CALLBACK
ERR_INVALID_CHAR
ERR_INVALID_CURSOR_POS
ERR_INVALID_FD
ERR_INVALID_FD_TYPE
ERR_INVALID_FILE_URL_HOST
ERR_INVALID_FILE_URL_PATH
ERR_INVALID_HANDLE_TYPE
ERR_INVALID_HTTP_TOKEN
ERR_INVALID_IP_ADDRESS
ERR_INVALID_MODULE_SPECIFIER
ERR_INVALID_OPT_VALUE
ERR_INVALID_OPT_VALUE_ENCODING
ERR_INVALID_PACKAGE_CONFIG
ERR_INVALID_PACKAGE_TARGET
ERR_INVALID_PERFORMANCE_MARK
ERR_INVALID_PROTOCOL
ERR_INVALID_REPL_EVAL_CONFIG
ERR_INVALID_REPL_INPUT
ERR_INVALID_RETURN_PROPERTY
ERR_INVALID_RETURN_PROPERTY_VALUE
ERR_INVALID_RETURN_VALUE
ERR_INVALID_SYNC_FORK_INPUT
ERR_INVALID_THIS
ERR_INVALID_TRANSFER_OBJECT
ERR_INVALID_TUPLE
ERR_INVALID_URI
ERR_INVALID_URL
ERR_INVALID_URL_SCHEME
ERR_IPC_CHANNEL_CLOSED
ERR_IPC_DISCONNECTED
ERR_IPC_ONE_PIPE
ERR_IPC_SYNC_FORK
ERR_MANIFEST_ASSERT_INTEGRITY
ERR_MANIFEST_DEPENDENCY_MISSING
ERR_MANIFEST_INTEGRITY_MISMATCH
ERR_MANIFEST_INVALID_RESOURCE_FIELD
ERR_MANIFEST_PARSE_POLICY
ERR_MANIFEST_TDZ
ERR_MANIFEST_UNKNOWN_ONERROR
ERR_MEMORY_ALLOCATION_FAILED
ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE
ERR_METHOD_NOT_IMPLEMENTED
ERR_MISSING_ARGS
ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK
ERR_MISSING_OPTION
ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
ERR_MISSING_PASSPHRASE
ERR_MISSING_PLATFORM_FOR_WORKER
ERR_MODULE_NOT_FOUND
ERR_MULTIPLE_CALLBACK
ERR_NAPI_CONS_FUNCTION
ERR_NAPI_INVALID_DATAVIEW_ARGS
ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT
ERR_NAPI_INVALID_TYPEDARRAY_LENGTH
ERR_NAPI_TSFN_CALL_JS
ERR_NAPI_TSFN_GET_UNDEFINED
ERR_NAPI_TSFN_START_IDLE_LOOP
ERR_NAPI_TSFN_STOP_IDLE_LOOP
ERR_NO_CRYPTO
ERR_NO_ICU
ERR_NON_CONTEXT_AWARE_DISABLED
ERR_OUT_OF_RANGE
ERR_PACKAGE_IMPORT_NOT_DEFINED
ERR_PACKAGE_PATH_NOT_EXPORTED
ERR_PROTO_ACCESS
ERR_REQUIRE_ESM
ERR_SCRIPT_EXECUTION_INTERRUPTED
ERR_SCRIPT_EXECUTION_TIMEOUT
ERR_SERVER_ALREADY_LISTEN
ERR_SERVER_NOT_RUNNING
ERR_SOCKET_ALREADY_BOUND
ERR_SOCKET_BAD_BUFFER_SIZE
ERR_SOCKET_BAD_PORT
ERR_SOCKET_BAD_TYPE
ERR_SOCKET_BUFFER_SIZE
ERR_SOCKET_CANNOT_SEND
ERR_SOCKET_CLOSED
ERR_SOCKET_DGRAM_IS_CONNECTED
ERR_SOCKET_DGRAM_NOT_CONNECTED
ERR_SOCKET_DGRAM_NOT_RUNNING
ERR_SRI_PARSE
ERR_STREAM_CANNOT_PIPE
ERR_STREAM_DESTROYED
ERR_STREAM_NULL_VALUES
ERR_STREAM_PREMATURE_CLOSE
ERR_STREAM_PUSH_AFTER_EOF
ERR_STREAM_UNSHIFT_AFTER_END_EVENT
ERR_STREAM_WRAP
ERR_STREAM_WRITE_AFTER_END
ERR_STRING_TOO_LONG
ERR_SYNTHETIC
ERR_SYSTEM_ERROR
ERR_TLS_CERT_ALTNAME_INVALID
ERR_TLS_DH_PARAM_SIZE
ERR_TLS_HANDSHAKE_TIMEOUT
ERR_TLS_INVALID_CONTEXT
ERR_TLS_INVALID_STATE
ERR_TLS_INVALID_PROTOCOL_METHOD
ERR_TLS_INVALID_PROTOCOL_VERSION
ERR_TLS_PROTOCOL_VERSION_CONFLICT
ERR_TLS_RENEGOTIATION_DISABLED
ERR_TLS_REQUIRED_SERVER_NAME
ERR_TLS_SESSION_ATTACK
ERR_TLS_SNI_FROM_SERVER
ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED
ERR_TRACE_EVENTS_CATEGORY_REQUIRED
ERR_TRACE_EVENTS_UNAVAILABLE
ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER
ERR_TRANSFORM_ALREADY_TRANSFORMING
ERR_TRANSFORM_WITH_LENGTH_0
ERR_TTY_INIT_FAILED
ERR_UNAVAILABLE_DURING_EXIT
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET
ERR_UNESCAPED_CHARACTERS
ERR_UNHANDLED_ERROR
ERR_UNKNOWN_BUILTIN_MODULE
ERR_UNKNOWN_CREDENTIAL
ERR_UNKNOWN_ENCODING
ERR_UNKNOWN_FILE_EXTENSION
ERR_UNKNOWN_MODULE_FORMAT
ERR_UNKNOWN_SIGNAL
ERR_UNSUPPORTED_DIR_IMPORT
ERR_UNSUPPORTED_ESM_URL_SCHEME
ERR_VALID_PERFORMANCE_ENTRY_TYPE
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
ERR_VM_MODULE_ALREADY_LINKED
ERR_VM_MODULE_CACHED_DATA_REJECTED
ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA
ERR_VM_MODULE_DIFFERENT_CONTEXT
ERR_VM_MODULE_LINKING_ERRORED
ERR_VM_MODULE_NOT_MODULE
ERR_VM_MODULE_STATUS
ERR_WASI_ALREADY_STARTED
ERR_WASI_NOT_STARTED
ERR_WORKER_INIT_FAILED
ERR_WORKER_INVALID_EXEC_ARGV
ERR_WORKER_NOT_RUNNING
ERR_WORKER_OUT_OF_MEMORY
ERR_WORKER_PATH
ERR_WORKER_UNSERIALIZABLE_ERROR
ERR_WORKER_UNSUPPORTED_EXTENSION
ERR_WORKER_UNSUPPORTED_OPERATION
ERR_ZLIB_INITIALIZATION_FAILED
HPE_HEADER_OVERFLOW
HPE_UNEXPECTED_CONTENT_LENGTH
MODULE_NOT_FOUND
- Legacy Node.js error codes
ERR_CANNOT_TRANSFER_OBJECT
ERR_CLOSED_MESSAGE_PORT
ERR_CRYPTO_HASH_DIGEST_NO_UTF16
ERR_HTTP2_FRAME_ERROR
ERR_HTTP2_HEADERS_OBJECT
ERR_HTTP2_HEADER_REQUIRED
ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND
ERR_HTTP2_STREAM_CLOSED
ERR_HTTP_INVALID_CHAR
ERR_INDEX_OUT_OF_RANGE
ERR_NAPI_CONS_PROTOTYPE_OBJECT
ERR_NO_LONGER_SUPPORTED
ERR_OUTOFMEMORY
ERR_PARSE_HISTORY_DATA
ERR_STDERR_CLOSE
ERR_STDOUT_CLOSE
ERR_STREAM_READ_NOT_IMPLEMENTED
ERR_TLS_RENEGOTIATION_FAILED
ERR_UNKNOWN_BUILTIN_MODULE
ERR_UNKNOWN_STDIN_TYPE
ERR_UNKNOWN_STREAM_TYPE
ERR_V8BREAKITERATOR
ERR_VALUE_OUT_OF_RANGE
ERR_VM_MODULE_NOT_LINKED
ERR_ZLIB_BINDING_CLOSED
- Events
- Passing arguments and
this
to listeners - Asynchronous vs. synchronous
- Handling events only once
- Error events
- Capture rejections of promises
- Class:
EventEmitter
- Event: 'newListener'
- Event:
'removeListener'
EventEmitter.listenerCount(emitter, eventName)
EventEmitter.defaultMaxListeners
EventEmitter.errorMonitor
emitter.addListener(eventName, listener)
emitter.emit(eventName[, ...args])
emitter.eventNames()
emitter.getMaxListeners()
emitter.listenerCount(eventName)
emitter.listeners(eventName)
emitter.off(eventName, listener)
emitter.on(eventName, listener)
emitter.once(eventName, listener)
emitter.prependListener(eventName, listener)
emitter.prependOnceListener(eventName, listener)
emitter.removeAllListeners([eventName])
emitter.removeListener(eventName, listener)
emitter.setMaxListeners(n)
emitter.rawListeners(eventName)
emitter[Symbol.for('nodejs.rejection')](err, eventName[, ...args])
events.once(emitter, name)
events.captureRejections
- events.captureRejectionSymbol
- events.on(emitter, eventName)
- Passing arguments and
- File system
- Synchronous example
- Callback example
- Promise example
- Ordering of callback and promise-based operations
- File paths
- File descriptors
- Threadpool usage
- Class:
fs.Dir
- Class:
fs.Dirent
- Class:
fs.FSWatcher
- Class:
fs.StatWatcher
- Class:
fs.ReadStream
- Class:
fs.Stats
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isDirectory()
stats.isFIFO()
stats.isFile()
stats.isSocket()
stats.isSymbolicLink()
stats.dev
stats.ino
stats.mode
stats.nlink
stats.uid
stats.gid
stats.rdev
stats.size
stats.blksize
stats.blocks
stats.atimeMs
stats.mtimeMs
stats.ctimeMs
stats.birthtimeMs
stats.atimeNs
stats.mtimeNs
stats.ctimeNs
stats.birthtimeNs
stats.atime
stats.mtime
stats.ctime
stats.birthtime
- Stat time values
- Class:
fs.WriteStream
fs.access(path[, mode], callback)
fs.accessSync(path[, mode])
fs.appendFile(path, data[, options], callback)
fs.appendFileSync(path, data[, options])
fs.chmod(path, mode, callback)
fs.chmodSync(path, mode)
fs.chown(path, uid, gid, callback)
fs.chownSync(path, uid, gid)
fs.close(fd, callback)
fs.closeSync(fd)
fs.constants
fs.copyFile(src, dest[, flags], callback)
fs.copyFileSync(src, dest[, flags])
fs.createReadStream(path[, options])
fs.createWriteStream(path[, options])
fs.exists(path, callback)
fs.existsSync(path)
fs.fchmod(fd, mode, callback)
fs.fchmodSync(fd, mode)
fs.fchown(fd, uid, gid, callback)
fs.fchownSync(fd, uid, gid)
fs.fdatasync(fd, callback)
fs.fdatasyncSync(fd)
fs.fstat(fd[, options], callback)
fs.fstatSync(fd[, options])
fs.fsync(fd, callback)
fs.fsyncSync(fd)
fs.ftruncate(fd[, len], callback)
fs.ftruncateSync(fd[, len])
fs.futimes(fd, atime, mtime, callback)
fs.futimesSync(fd, atime, mtime)
fs.lchmod(path, mode, callback)
fs.lchmodSync(path, mode)
fs.lchown(path, uid, gid, callback)
fs.lchownSync(path, uid, gid)
fs.lutimes(path, atime, mtime, callback)
fs.lutimesSync(path, atime, mtime)
fs.link(existingPath, newPath, callback)
fs.linkSync(existingPath, newPath)
fs.lstat(path[, options], callback)
fs.lstatSync(path[, options])
fs.mkdir(path[, options], callback)
fs.mkdirSync(path[, options])
fs.mkdtemp(prefix[, options], callback)
fs.mkdtempSync(prefix[, options])
fs.open(path[, flags[, mode]], callback)
fs.opendir(path[, options], callback)
fs.opendirSync(path[, options])
fs.openSync(path[, flags, mode])
fs.read(fd, buffer, offset, length, position, callback)
fs.read(fd, [options,] callback)
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
fs.readFile(path[, options], callback)
fs.readFileSync(path[, options])
fs.readlink(path[, options], callback)
fs.readlinkSync(path[, options])
fs.readSync(fd, buffer, offset, length, position)
fs.readSync(fd, buffer, [options])
fs.readv(fd, buffers[, position], callback)
fs.readvSync(fd, buffers[, position])
fs.realpath(path[, options], callback)
fs.realpath.native(path[, options], callback)
fs.realpathSync(path[, options])
fs.realpathSync.native(path[, options])
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath)
fs.rmdir(path[, options], callback)
fs.rmdirSync(path[, options])
fs.stat(path[, options], callback)
fs.statSync(path[, options])
fs.symlink(target, path[, type], callback)
fs.symlinkSync(target, path[, type])
fs.truncate(path[, len], callback)
fs.truncateSync(path[, len])
fs.unlink(path, callback)
fs.unlinkSync(path)
fs.unwatchFile(filename[, listener])
fs.utimes(path, atime, mtime, callback)
fs.utimesSync(path, atime, mtime)
fs.watch(filename[, options][, listener])
fs.watchFile(filename[, options], listener)
fs.write(fd, buffer[, offset[, length[, position]]], callback)
fs.write(fd, string[, position[, encoding]], callback)
fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])
fs.writeSync(fd, buffer[, offset[, length[, position]]])
fs.writeSync(fd, string[, position[, encoding]])
fs.writev(fd, buffers[, position], callback)
fs.writevSync(fd, buffers[, position])
fs
Promises API- Class:
FileHandle
filehandle.appendFile(data, options)
filehandle.chmod(mode)
filehandle.chown(uid, gid)
filehandle.close()
filehandle.datasync()
filehandle.fd
filehandle.read(buffer, offset, length, position)
filehandle.read(options)
filehandle.readFile(options)
filehandle.readv(buffers[, position])
filehandle.stat([options])
filehandle.sync()
filehandle.truncate(len)
filehandle.utimes(atime, mtime)
filehandle.write(buffer[, offset[, length[, position]]])
filehandle.write(string[, position[, encoding]])
filehandle.writeFile(data, options)
filehandle.writev(buffers[, position])
fsPromises.access(path[, mode])
fsPromises.appendFile(path, data[, options])
fsPromises.chmod(path, mode)
fsPromises.chown(path, uid, gid)
fsPromises.copyFile(src, dest[, flags])
fsPromises.lchmod(path, mode)
fsPromises.lchown(path, uid, gid)
fsPromises.lutimes(path, atime, mtime)
fsPromises.link(existingPath, newPath)
fsPromises.lstat(path[, options])
fsPromises.mkdir(path[, options])
fsPromises.mkdtemp(prefix[, options])
fsPromises.open(path, flags[, mode])
fsPromises.opendir(path[, options])
fsPromises.readdir(path[, options])
fsPromises.readFile(path[, options])
fsPromises.readlink(path[, options])
fsPromises.realpath(path[, options])
fsPromises.rename(oldPath, newPath)
fsPromises.rmdir(path[, options])
fsPromises.stat(path[, options])
fsPromises.symlink(target, path[, type])
fsPromises.truncate(path[, len])
fsPromises.unlink(path)
fsPromises.utimes(path, atime, mtime)
fsPromises.writeFile(file, data[, options])
- Class:
- FS constants
- File system flags
- Global objects
- Class:
Buffer
__dirname
__filename
clearImmediate(immediateObject)
clearInterval(intervalObject)
clearTimeout(timeoutObject)
console
exports
global
module
process
queueMicrotask(callback)
require()
setImmediate(callback[, ...args])
setInterval(callback, delay[, ...args])
setTimeout(callback, delay[, ...args])
TextDecoder
TextEncoder
URL
URLSearchParams
WebAssembly
- Class:
- HTTP
- Class:
http.Agent
- Class:
http.ClientRequest
- Event:
'abort'
- Event:
'connect'
- Event:
'continue'
- Event:
'information'
- Event:
'response'
- Event:
'socket'
- Event:
'timeout'
- Event:
'upgrade'
request.abort()
request.aborted
request.connection
request.end([data[, encoding]][, callback])
request.finished
request.flushHeaders()
request.getHeader(name)
request.maxHeadersCount
request.path
request.method
request.host
request.protocol
request.removeHeader(name)
request.reusedSocket
request.setHeader(name, value)
request.setNoDelay([noDelay])
request.setSocketKeepAlive([enable][, initialDelay])
request.setTimeout(timeout[, callback])
request.socket
request.writableEnded
request.writableFinished
request.write(chunk[, encoding][, callback])
- Event:
- Class:
http.Server
- Event:
'checkContinue'
- Event:
'checkExpectation'
- Event:
'clientError'
- Event:
'close'
- Event:
'connect'
- Event:
'connection'
- Event:
'request'
- Event:
'upgrade'
server.close([callback])
server.headersTimeout
server.listen()
server.listening
server.maxHeadersCount
server.setTimeout([msecs][, callback])
server.timeout
server.keepAliveTimeout
- Event:
- Class:
http.ServerResponse
- Event:
'close'
- Event:
'finish'
response.addTrailers(headers)
response.connection
response.cork()
response.end([data[, encoding]][, callback])
response.finished
response.flushHeaders()
response.getHeader(name)
response.getHeaderNames()
response.getHeaders()
response.hasHeader(name)
response.headersSent
response.removeHeader(name)
response.sendDate
response.setHeader(name, value)
response.setTimeout(msecs[, callback])
response.socket
response.statusCode
response.statusMessage
response.uncork()
response.writableEnded
response.writableFinished
response.write(chunk[, encoding][, callback])
response.writeContinue()
response.writeHead(statusCode[, statusMessage][, headers])
response.writeProcessing()
- Event:
- Class:
http.IncomingMessage
- Event:
'aborted'
- Event:
'close'
message.aborted
message.complete
message.destroy([error])
message.headers
message.httpVersion
message.method
message.rawHeaders
message.rawTrailers
message.setTimeout(msecs[, callback])
message.socket
message.statusCode
message.statusMessage
message.trailers
message.url
- Event:
http.METHODS
http.STATUS_CODES
http.createServer([options][, requestListener])
http.get(options[, callback])
http.get(url[, options][, callback])
http.globalAgent
http.maxHeaderSize
http.request(options[, callback])
http.request(url[, options][, callback])
- Class:
- HTTP/2
- Core API
- Server-side example
- Client-side example
- Class:
Http2Session
Http2Session
and sockets- Event:
'close'
- Event:
'connect'
- Event:
'error'
- Event:
'frameError'
- Event:
'goaway'
- Event:
'localSettings'
- Event:
'ping'
- Event:
'remoteSettings'
- Event:
'stream'
- Event:
'timeout'
http2session.alpnProtocol
http2session.close([callback])
http2session.closed
http2session.connecting
http2session.destroy([error][, code])
http2session.destroyed
http2session.encrypted
http2session.goaway([code[, lastStreamID[, opaqueData]]])
http2session.localSettings
http2session.originSet
http2session.pendingSettingsAck
http2session.ping([payload, ]callback)
http2session.ref()
http2session.remoteSettings
http2session.setTimeout(msecs, callback)
http2session.socket
http2session.state
http2session.settings([settings][, callback])
http2session.type
http2session.unref()
- Class:
ServerHttp2Session
- Class:
ClientHttp2Session
- Class:
Http2Stream
Http2Stream
Lifecycle- Event:
'aborted'
- Event:
'close'
- Event:
'error'
- Event:
'frameError'
- Event:
'ready'
- Event:
'timeout'
- Event:
'trailers'
- Event:
'wantTrailers'
http2stream.aborted
http2stream.bufferSize
http2stream.close(code[, callback])
http2stream.closed
http2stream.destroyed
http2stream.endAfterHeaders
http2stream.id
http2stream.pending
http2stream.priority(options)
http2stream.rstCode
http2stream.sentHeaders
http2stream.sentInfoHeaders
http2stream.sentTrailers
http2stream.session
http2stream.setTimeout(msecs, callback)
http2stream.state
http2stream.sendTrailers(headers)
- Class:
ClientHttp2Stream
- Class:
ServerHttp2Stream
- Class:
Http2Server
- Event:
'connection'
- Class:
Http2SecureServer
- Event:
'connection'
http2.createServer(options[, onRequestHandler])
http2.createSecureServer(options[, onRequestHandler])
http2.connect(authority[, options][, listener])
http2.constants
http2.getDefaultSettings()
http2.getPackedSettings([settings])
http2.getUnpackedSettings(buf)
- Headers object
- Settings object
- Using
options.selectPadding()
- Error handling
- Invalid character handling in header names and values
- Push streams on the client
- Supporting the
CONNECT
method - The extended
CONNECT
protocol
- Compatibility API
- ALPN negotiation
- Class:
http2.Http2ServerRequest
- Event:
'aborted'
- Event:
'close'
request.aborted
request.authority
request.complete
request.destroy([error])
request.headers
request.httpVersion
request.method
request.rawHeaders
request.rawTrailers
request.scheme
request.setTimeout(msecs, callback)
request.socket
request.stream
request.trailers
request.url
- Event:
- Class:
http2.Http2ServerResponse
- Event:
'close'
- Event:
'finish'
response.addTrailers(headers)
response.connection
response.end([data[, encoding]][, callback])
response.finished
response.getHeader(name)
response.getHeaderNames()
response.getHeaders()
response.hasHeader(name)
response.headersSent
response.removeHeader(name)
response.sendDate
response.setHeader(name, value)
response.setTimeout(msecs[, callback])
response.socket
response.statusCode
response.statusMessage
response.stream
response.writableEnded
response.write(chunk[, encoding][, callback])
response.writeContinue()
response.writeHead(statusCode[, statusMessage][, headers])
response.createPushResponse(headers, callback)
- Event:
- Collecting HTTP/2 performance metrics
- Core API
- HTTPS
- Inspector
- Internationalization support
- Modules: CommonJS modules
- Accessing the main module
- Addenda: Package manager tips
- Addenda: The
.mjs
extension - All together...
- Caching
- Core modules
- Cycles
- File modules
- Folders as modules
- Loading from
node_modules
folders - Loading from the global folders
- The module wrapper
- The module scope
- The
module
object - The
Module
object - Source map v3 support
- Modules: ECMAScript modules
- Introduction
- Enabling
- Packages
import
Specifiersimport.meta
- Differences between ES modules and CommonJS
- Interoperability with CommonJS
- CommonJS Namespaces
- Builtin modules
- CommonJS, JSON, and native modules
- Experimental JSON modules
- Experimental Wasm modules
- Experimental loaders
- Resolution algorithm
- Modules:
module
API - Modules: Packages
- Net
- IPC support
- Class:
net.Server
- Class:
net.Socket
new net.Socket([options])
- Event:
'close'
- Event:
'connect'
- Event:
'data'
- Event:
'drain'
- Event:
'end'
- Event:
'error'
- Event:
'lookup'
- Event:
'ready'
- Event:
'timeout'
socket.address()
socket.bufferSize
socket.bytesRead
socket.bytesWritten
socket.connect()
socket.connecting
socket.destroy([error])
socket.destroyed
socket.end([data[, encoding]][, callback])
socket.localAddress
socket.localPort
socket.pause()
socket.pending
socket.ref()
socket.remoteAddress
socket.remoteFamily
socket.remotePort
socket.resume()
socket.setEncoding([encoding])
socket.setKeepAlive([enable][, initialDelay])
socket.setNoDelay([noDelay])
socket.setTimeout(timeout[, callback])
socket.unref()
socket.write(data[, encoding][, callback])
net.connect()
net.createConnection()
net.createServer([options][, connectionListener])
net.isIP(input)
net.isIPv4(input)
net.isIPv6(input)
- OS
os.EOL
os.arch()
os.constants
os.cpus()
os.endianness()
os.freemem()
os.getPriority([pid])
os.homedir()
os.hostname()
os.loadavg()
os.networkInterfaces()
os.platform()
os.release()
os.setPriority([pid, ]priority)
os.tmpdir()
os.totalmem()
os.type()
os.uptime()
os.userInfo([options])
os.version()
- OS constants
- Path
- Windows vs. POSIX
path.basename(path[, ext])
path.delimiter
path.dirname(path)
path.extname(path)
path.format(pathObject)
path.isAbsolute(path)
path.join([...paths])
path.normalize(path)
path.parse(path)
path.posix
path.relative(from, to)
path.resolve([...paths])
path.sep
path.toNamespacedPath(path)
path.win32
- Performance measurement APIs
perf_hooks.performance
performance.clearMarks([name])
performance.eventLoopUtilization([utilization1[, utilization2]])
performance.mark([name])
performance.measure(name[, startMark[, endMark]])
performance.nodeTiming
performance.now()
performance.timeOrigin
performance.timerify(fn)
performance.eventLoopUtilization([util1][,util2])
- Class:
PerformanceEntry
- Class:
PerformanceNodeTiming extends PerformanceEntry
- Class:
perf_hooks.PerformanceObserver
- Class:
PerformanceObserverEntryList
perf_hooks.monitorEventLoopDelay([options])
- Examples
- Policies
- Process
- Process events
process.abort()
process.allowedNodeEnvironmentFlags
process.arch
process.argv
process.argv0
process.channel
process.chdir(directory)
process.config
process.connected
process.cpuUsage([previousValue])
process.cwd()
process.debugPort
process.disconnect()
process.dlopen(module, filename[, flags])
process.emitWarning(warning[, options])
process.emitWarning(warning[, type[, code]][, ctor])
process.env
process.execArgv
process.execPath
process.exit([code])
process.exitCode
process.getegid()
process.geteuid()
process.getgid()
process.getgroups()
process.getuid()
process.hasUncaughtExceptionCaptureCallback()
process.hrtime([time])
process.hrtime.bigint()
process.initgroups(user, extraGroup)
process.kill(pid[, signal])
process.mainModule
process.memoryUsage()
process.nextTick(callback[, ...args])
process.noDeprecation
process.pid
process.platform
process.ppid
process.release
process.report
process.resourceUsage()
process.send(message[, sendHandle[, options]][, callback])
process.setegid(id)
process.seteuid(id)
process.setgid(id)
process.setgroups(groups)
process.setuid(id)
process.setUncaughtExceptionCaptureCallback(fn)
process.stderr
process.stdin
process.stdout
process.throwDeprecation
process.title
process.traceDeprecation
process.umask()
process.umask(mask)
process.uptime()
process.version
process.versions
- Exit codes
- Punycode
- Query string
- Readline
- Class:
Interface
- Event:
'close'
- Event:
'line'
- Event:
'pause'
- Event:
'resume'
- Event:
'SIGCONT'
- Event:
'SIGINT'
- Event:
'SIGTSTP'
rl.close()
rl.pause()
rl.prompt([preserveCursor])
rl.question(query, callback)
rl.resume()
rl.setPrompt(prompt)
rl.write(data[, key])
rl[Symbol.asyncIterator]()
- rl.line
- rl.cursor
rl.getCursorPos()
- Event:
readline.clearLine(stream, dir[, callback])
readline.clearScreenDown(stream[, callback])
readline.createInterface(options)
readline.cursorTo(stream, x[, y][, callback])
readline.emitKeypressEvents(stream[, interface])
readline.moveCursor(stream, dx, dy[, callback])
- Example: Tiny CLI
- Example: Read file stream line-by-Line
- TTY keybindings
- Class:
- REPL
- Diagnostic report
- Stream
- Organization of this document
- Types of streams
- API for stream consumers
- Writable streams
- Class:
stream.Writable
- Event:
'close'
- Event:
'drain'
- Event:
'error'
- Event:
'finish'
- Event:
'pipe'
- Event:
'unpipe'
writable.cork()
writable.destroy([error])
writable.destroyed
writable.end([chunk[, encoding]][, callback])
writable.setDefaultEncoding(encoding)
writable.uncork()
writable.writable
writable.writableEnded
writable.writableCorked
writable.writableFinished
writable.writableHighWaterMark
writable.writableLength
writable.writableObjectMode
writable.write(chunk[, encoding][, callback])
- Event:
- Class:
- Readable streams
- Two reading modes
- Three states
- Choose one API style
- Class:
stream.Readable
- Event:
'close'
- Event:
'data'
- Event:
'end'
- Event:
'error'
- Event:
'pause'
- Event:
'readable'
- Event:
'resume'
readable.destroy([error])
readable.destroyed
readable.isPaused()
readable.pause()
readable.pipe(destination[, options])
readable.read([size])
readable.readable
readable.readableEncoding
readable.readableEnded
readable.readableFlowing
readable.readableHighWaterMark
readable.readableLength
readable.readableObjectMode
readable.resume()
readable.setEncoding(encoding)
readable.unpipe([destination])
readable.unshift(chunk[, encoding])
readable.wrap(stream)
readable[Symbol.asyncIterator]()
- Event:
- Duplex and transform streams
stream.finished(stream[, options], callback)
stream.pipeline(...streams, callback)
stream.Readable.from(iterable, [options])
- Writable streams
- API for stream implementers
- Additional notes
- String decoder
- Timers
- TLS (SSL)
- TLS/SSL concepts
- Modifying the default TLS cipher suite
- Class:
tls.CryptoStream
- Class:
tls.SecurePair
- Class:
tls.Server
- Event:
'connection'
- Event:
'keylog'
- Event:
'newSession'
- Event:
'OCSPRequest'
- Event:
'resumeSession'
- Event:
'secureConnection'
- Event:
'tlsClientError'
server.addContext(hostname, context)
server.address()
server.close([callback])
server.connections
server.getTicketKeys()
server.listen()
server.setSecureContext(options)
server.setTicketKeys(keys)
- Event:
- Class:
tls.TLSSocket
new tls.TLSSocket(socket[, options])
- Event:
'keylog'
- Event:
'OCSPResponse'
- Event:
'secureConnect'
- Event:
'session'
tlsSocket.address()
tlsSocket.authorizationError
tlsSocket.authorized
tlsSocket.disableRenegotiation()
tlsSocket.enableTrace()
tlsSocket.encrypted
tlsSocket.getCertificate()
tlsSocket.getCipher()
tlsSocket.getEphemeralKeyInfo()
tlsSocket.getFinished()
tlsSocket.getPeerCertificate([detailed])
tlsSocket.getPeerFinished()
tlsSocket.getProtocol()
tlsSocket.getSession()
tlsSocket.getSharedSigalgs()
tlsSocket.exportKeyingMaterial(length, label[, context])
tlsSocket.getTLSTicket()
tlsSocket.isSessionReused()
tlsSocket.localAddress
tlsSocket.localPort
tlsSocket.remoteAddress
tlsSocket.remoteFamily
tlsSocket.remotePort
tlsSocket.renegotiate(options, callback)
tlsSocket.setMaxSendFragment(size)
tls.checkServerIdentity(hostname, cert)
tls.connect(options[, callback])
tls.connect(path[, options][, callback])
tls.connect(port[, host][, options][, callback])
tls.createSecureContext([options])
tls.createSecurePair([context][, isServer][, requestCert][, rejectUnauthorized][, options])
tls.createServer([options][, secureConnectionListener])
tls.getCiphers()
tls.rootCertificates
tls.DEFAULT_ECDH_CURVE
tls.DEFAULT_MAX_VERSION
tls.DEFAULT_MIN_VERSION
- Trace events
- TTY
- Class:
tty.ReadStream
- Class:
tty.WriteStream
- Event:
'resize'
writeStream.clearLine(dir[, callback])
writeStream.clearScreenDown([callback])
writeStream.columns
writeStream.cursorTo(x[, y][, callback])
writeStream.getColorDepth([env])
writeStream.getWindowSize()
writeStream.hasColors([count][, env])
writeStream.isTTY
writeStream.moveCursor(dx, dy[, callback])
writeStream.rows
- Event:
tty.isatty(fd)
- Class:
- UDP/datagram sockets
- Class:
dgram.Socket
- Event:
'close'
- Event:
'connect'
- Event:
'error'
- Event:
'listening'
- Event:
'message'
socket.addMembership(multicastAddress[, multicastInterface])
socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
socket.address()
socket.bind([port][, address][, callback])
socket.bind(options[, callback])
socket.close([callback])
socket.connect(port[, address][, callback])
socket.disconnect()
socket.dropMembership(multicastAddress[, multicastInterface])
socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
socket.getRecvBufferSize()
socket.getSendBufferSize()
socket.ref()
socket.remoteAddress()
socket.send(msg[, offset, length][, port][, address][, callback])
socket.setBroadcast(flag)
socket.setMulticastInterface(multicastInterface)
socket.setMulticastLoopback(flag)
socket.setMulticastTTL(ttl)
socket.setRecvBufferSize(size)
socket.setSendBufferSize(size)
socket.setTTL(ttl)
socket.unref()
- Event:
dgram
module functions
- Class:
- URL
- URL strings and URL objects
- The WHATWG URL API
- Class:
URL
- Class:
URLSearchParams
new URLSearchParams()
new URLSearchParams(string)
new URLSearchParams(obj)
new URLSearchParams(iterable)
urlSearchParams.append(name, value)
urlSearchParams.delete(name)
urlSearchParams.entries()
urlSearchParams.forEach(fn[, thisArg])
urlSearchParams.get(name)
urlSearchParams.getAll(name)
urlSearchParams.has(name)
urlSearchParams.keys()
urlSearchParams.set(name, value)
urlSearchParams.sort()
urlSearchParams.toString()
urlSearchParams.values()
urlSearchParams[Symbol.iterator]()
url.domainToASCII(domain)
url.domainToUnicode(domain)
url.fileURLToPath(url)
url.format(URL[, options])
url.pathToFileURL(path)
- Class:
- Legacy URL API
- Percent-encoding in URLs
- Util
util.callbackify(original)
util.debuglog(section[, callback])
util.deprecate(fn, msg[, code])
util.format(format[, ...args])
util.formatWithOptions(inspectOptions, format[, ...args])
util.getSystemErrorName(err)
util.inherits(constructor, superConstructor)
util.inspect(object[, options])
util.inspect(object[, showHidden[, depth[, colors]]])
util.isDeepStrictEqual(val1, val2)
util.promisify(original)
- Class:
util.TextDecoder
- Class:
util.TextEncoder
util.types
util.types.isAnyArrayBuffer(value)
util.types.isArrayBufferView(value)
util.types.isArgumentsObject(value)
util.types.isArrayBuffer(value)
util.types.isAsyncFunction(value)
util.types.isBigInt64Array(value)
util.types.isBigUint64Array(value)
util.types.isBooleanObject(value)
util.types.isBoxedPrimitive(value)
util.types.isDataView(value)
util.types.isDate(value)
util.types.isExternal(value)
util.types.isFloat32Array(value)
util.types.isFloat64Array(value)
util.types.isGeneratorFunction(value)
util.types.isGeneratorObject(value)
util.types.isInt8Array(value)
util.types.isInt16Array(value)
util.types.isInt32Array(value)
util.types.isMap(value)
util.types.isMapIterator(value)
util.types.isModuleNamespaceObject(value)
util.types.isNativeError(value)
util.types.isNumberObject(value)
util.types.isPromise(value)
util.types.isProxy(value)
util.types.isRegExp(value)
util.types.isSet(value)
util.types.isSetIterator(value)
util.types.isSharedArrayBuffer(value)
util.types.isStringObject(value)
util.types.isSymbolObject(value)
util.types.isTypedArray(value)
util.types.isUint8Array(value)
util.types.isUint8ClampedArray(value)
util.types.isUint16Array(value)
util.types.isUint32Array(value)
util.types.isWeakMap(value)
util.types.isWeakSet(value)
util.types.isWebAssemblyCompiledModule(value)
- Deprecated APIs
util._extend(target, source)
util.isArray(object)
util.isBoolean(object)
util.isBuffer(object)
util.isDate(object)
util.isError(object)
util.isFunction(object)
util.isNull(object)
util.isNullOrUndefined(object)
util.isNumber(object)
util.isObject(object)
util.isPrimitive(object)
util.isRegExp(object)
util.isString(object)
util.isSymbol(object)
util.isUndefined(object)
util.log(string)
- V8
v8.cachedDataVersionTag()
v8.getHeapSpaceStatistics()
v8.getHeapSnapshot()
v8.getHeapStatistics()
v8.getHeapCodeStatistics()
v8.setFlagsFromString(flags)
v8.takeCoverage()
v8.stopCoverage()
v8.writeHeapSnapshot([filename])
- Serialization API
v8.serialize(value)
v8.deserialize(buffer)
- Class:
v8.Serializer
new Serializer()
serializer.writeHeader()
serializer.writeValue(value)
serializer.releaseBuffer()
serializer.transferArrayBuffer(id, arrayBuffer)
serializer.writeUint32(value)
serializer.writeUint64(hi, lo)
serializer.writeDouble(value)
serializer.writeRawBytes(buffer)
serializer._writeHostObject(object)
serializer._getDataCloneError(message)
serializer._getSharedArrayBufferId(sharedArrayBuffer)
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
- Class:
v8.Deserializer
new Deserializer(buffer)
deserializer.readHeader()
deserializer.readValue()
deserializer.transferArrayBuffer(id, arrayBuffer)
deserializer.getWireFormatVersion()
deserializer.readUint32()
deserializer.readUint64()
deserializer.readDouble()
deserializer.readRawBytes(length)
deserializer._readHostObject()
- Class:
v8.DefaultSerializer
- Class:
v8.DefaultDeserializer
- VM (executing JavaScript)
- Class:
vm.Script
- Class:
vm.Module
- Class:
vm.SourceTextModule
- Class:
vm.SyntheticModule
vm.compileFunction(code[, params[, options]])
vm.createContext([contextObject[, options]])
vm.isContext(object)
vm.runInContext(code, contextifiedObject[, options])
vm.runInNewContext(code[, contextObject[, options]])
vm.runInThisContext(code[, options])
- Example: Running an HTTP server within a VM
- What does it mean to "contextify" an object?
- Timeout limitations when using
process.nextTick()
, promises, andqueueMicrotask()
- Class:
- WebAssembly System Interface (WASI)
- Worker threads
worker.isMainThread
worker.markAsUntransferable(object)
worker.moveMessagePortToContext(port, contextifiedSandbox)
worker.parentPort
worker.receiveMessageOnPort(port)
worker.resourceLimits
worker.SHARE_ENV
worker.threadId
worker.workerData
- Class:
MessageChannel
- Class:
MessagePort
- Class:
Worker
new Worker(filename[, options])
- Event:
'error'
- Event:
'exit'
- Event:
'message'
- Event:
'messageerror'
- Event:
'online'
worker.getHeapSnapshot()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.unref()
- Zlib
- Threadpool usage and performance considerations
- Compressing HTTP requests and responses
- Memory usage tuning
- Flushing
- Constants
- Class:
Options
- Class:
BrotliOptions
- Class:
zlib.BrotliCompress
- Class:
zlib.BrotliDecompress
- Class:
zlib.Deflate
- Class:
zlib.DeflateRaw
- Class:
zlib.Gunzip
- Class:
zlib.Gzip
- Class:
zlib.Inflate
- Class:
zlib.InflateRaw
- Class:
zlib.Unzip
- Class:
zlib.ZlibBase
zlib.constants
zlib.createBrotliCompress([options])
zlib.createBrotliDecompress([options])
zlib.createDeflate([options])
zlib.createDeflateRaw([options])
zlib.createGunzip([options])
zlib.createGzip([options])
zlib.createInflate([options])
zlib.createInflateRaw([options])
zlib.createUnzip([options])
- Convenience methods
zlib.brotliCompress(buffer[, options], callback)
zlib.brotliCompressSync(buffer[, options])
zlib.brotliDecompress(buffer[, options], callback)
zlib.brotliDecompressSync(buffer[, options])
zlib.deflate(buffer[, options], callback)
zlib.deflateSync(buffer[, options])
zlib.deflateRaw(buffer[, options], callback)
zlib.deflateRawSync(buffer[, options])
zlib.gunzip(buffer[, options], callback)
zlib.gunzipSync(buffer[, options])
zlib.gzip(buffer[, options], callback)
zlib.gzipSync(buffer[, options])
zlib.inflate(buffer[, options], callback)
zlib.inflateSync(buffer[, options])
zlib.inflateRaw(buffer[, options], callback)
zlib.inflateRawSync(buffer[, options])
zlib.unzip(buffer[, options], callback)
zlib.unzipSync(buffer[, options])
About this documentation#
Welcome to the official API reference documentation for Node.js!
Node.js is a JavaScript runtime built on the V8 JavaScript engine.
Contributing#
Report errors in this documentation in the issue tracker. See the contributing guide for directions on how to submit pull requests.
Stability index#
Throughout the documentation are indications of a section's stability. Some APIs are so proven and so relied upon that they are unlikely to ever change at all. Others are brand new and experimental, or known to be hazardous.
The stability indices are as follows:
Use caution when making use of Experimental features, particularly within modules. Users may not be aware that experimental features are being used. Bugs or behavior changes may surprise users when Experimental API modifications occur. To avoid surprises, use of an Experimental feature may need a command-line flag. Experimental features may also emit a warning.
JSON output#
Every .html
document has a corresponding .json
document. This is for IDEs
and other utilities that consume the documentation.
System calls and man pages#
Node.js functions which wrap a system call will document that. The docs link to the corresponding man pages which describe how the system call works.
Most Unix system calls have Windows analogues. Still, behavior differences may be unavoidable.
Usage and example#
Usage#
node [options] [V8 options] [script.js | -e "script" | - ] [arguments]
Please see the Command Line Options document for more information.
Example#
An example of a web server written with Node.js which responds with
'Hello, World!'
:
Commands in this document start with $
or >
to replicate how they would
appear in a user's terminal. Do not include the $
and >
characters. They are
there to show the start of each command.
Lines that don’t start with $
or >
character show the output of the previous
command.
First, make sure to have downloaded and installed Node.js. See this guide for further install information.
Now, create an empty project folder called projects
, then navigate into it.
Linux and Mac:
$ mkdir ~/projects
$ cd ~/projects
Windows CMD:
> mkdir %USERPROFILE%\projects
> cd %USERPROFILE%\projects
Windows PowerShell:
> mkdir $env:USERPROFILE\projects
> cd $env:USERPROFILE\projects
Next, create a new source file in the projects
folder and call it hello-world.js
.
Open hello-world.js
in any preferred text editor and
paste in the following content:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Save the file, go back to the terminal window, and enter the following command:
$ node hello-world.js
Output like this should appear in the terminal:
Server running at http://127.0.0.1:3000/
Now, open any preferred web browser and visit http://127.0.0.1:3000
.
If the browser displays the string Hello, World!
, that indicates
the server is working.
Assert#
Source Code: lib/assert.js
The assert
module provides a set of assertion functions for verifying
invariants.
Strict assertion mode#
In strict assertion mode, non-strict methods behave like their corresponding
strict methods. For example, assert.deepEqual()
will behave like
assert.deepStrictEqual()
.
In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error messages for objects display the objects, often truncated.
To use strict assertion mode:
const assert = require('assert').strict;
Example error diff:
const assert = require('assert').strict;
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
To deactivate the colors, use the NO_COLOR
or NODE_DISABLE_COLORS
environment variables. This will also deactivate the colors in the REPL. For
more on color support in terminal environments, read the tty
getColorDepth() documentation.
Legacy assertion mode#
Legacy assertion mode uses the Abstract Equality Comparison in:
To use legacy assertion mode:
const assert = require('assert');
Whenever possible, use the strict assertion mode instead. Otherwise, the
Abstract Equality Comparison may cause surprising results. This is
especially true for assert.deepEqual()
, where the comparison rules are
lax:
// WARNING: This does not throw an AssertionError!
assert.deepEqual(/a/gi, new Date());
Class: assert.AssertionError[src]#
- Extends: <errors.Error>
Indicates the failure of an assertion. All errors thrown by the assert
module
will be instances of the AssertionError
class.
new assert.AssertionError(options)
#
options
<Object>message
<string> If provided, the error message is set to this value.actual
<any> Theactual
property on the error instance.expected
<any> Theexpected
property on the error instance.operator
<string> Theoperator
property on the error instance.stackStartFn
<Function> If provided, the generated stack trace omits frames before this function.
A subclass of Error
that indicates the failure of an assertion.
All instances contain the built-in Error
properties (message
and name
)
and:
actual
<any> Set to theactual
argument for methods such asassert.strictEqual()
.expected
<any> Set to theexpected
value for methods such asassert.strictEqual()
.generatedMessage
<boolean> Indicates if the message was auto-generated (true
) or not.code
<string> Value is alwaysERR_ASSERTION
to show that the error is an assertion error.operator
<string> Set to the passed in operator value.
const assert = require('assert');
// Generate an AssertionError to compare the error message later:
const { message } = new assert.AssertionError({
actual: 1,
expected: 2,
operator: 'strictEqual'
});
// Verify error output:
try {
assert.strictEqual(1, 2);
} catch (err) {
assert(err instanceof assert.AssertionError);
assert.strictEqual(err.message, message);
assert.strictEqual(err.name, 'AssertionError');
assert.strictEqual(err.actual, 1);
assert.strictEqual(err.expected, 2);
assert.strictEqual(err.code, 'ERR_ASSERTION');
assert.strictEqual(err.operator, 'strictEqual');
assert.strictEqual(err.generatedMessage, true);
}
Class: assert.CallTracker
#
This feature is currently experimental and behavior might still change.
### new assert.CallTracker()
Creates a new CallTracker
object which can be used to track if functions
were called a specific number of times. The tracker.verify()
must be called
for the verification to take place. The usual pattern would be to call it in a
process.on('exit')
handler.
const assert = require('assert');
const tracker = new assert.CallTracker();
function func() {}
// callsfunc() must be called exactly 1 time before tracker.verify().
const callsfunc = tracker.calls(func, 1);
callsfunc();
// Calls tracker.verify() and verifies if all tracker.calls() functions have
// been called exact times.
process.on('exit', () => {
tracker.verify();
});
tracker.calls([fn][, exact])
#
fn
<Function> Default A no-op function.exact
<number> Default1
.- Returns: <Function> that wraps
fn
.
The wrapper function is expected to be called exactly exact
times. If the
function has not been called exactly exact
times when
tracker.verify()
is called, then tracker.verify()
will throw an
error.
const assert = require('assert');
// Creates call tracker.
const tracker = new assert.CallTracker();
function func() {}
// Returns a function that wraps func() that must be called exact times
// before tracker.verify().
const callsfunc = tracker.calls(func);
tracker.report()
#
- Returns: <Array> of objects containing information about the wrapper functions
returned by
tracker.calls()
. - Object <Object>
The arrays contains information about the expected and actual number of calls of the functions that have not been called the expected number of times.
const assert = require('assert');
// Creates call tracker.
const tracker = new assert.CallTracker();
function func() {}
function foo() {}
// Returns a function that wraps func() that must be called exact times
// before tracker.verify().
const callsfunc = tracker.calls(func, 2);
// Returns an array containing information on callsfunc()
tracker.report();
// [
// {
// message: 'Expected the func function to be executed 2 time(s) but was
// executed 0 time(s).',
// actual: 0,
// expected: 2,
// operator: 'func',
// stack: stack trace
// }
// ]
tracker.verify()
#
Iterates through the list of functions passed to
tracker.calls()
and will throw an error for functions that
have not been called the expected number of times.
const assert = require('assert');
// Creates call tracker.
const tracker = new assert.CallTracker();
function func() {}
// Returns a function that wraps func() that must be called exact times
// before tracker.verify().
const callsfunc = tracker.calls(func, 2);
callsfunc();
// Will throw an error since callsfunc() was only called once.
tracker.verify();
assert(value[, message])
#
An alias of assert.ok()
.
assert.deepEqual(actual, expected[, message])
#
Strict assertion mode
An alias of assert.deepStrictEqual()
.
Legacy assertion mode
assert.deepStrictEqual()
instead.Tests for deep equality between the actual
and expected
parameters. Consider
using assert.deepStrictEqual()
instead. assert.deepEqual()
can have
surprising results.
Deep equality means that the enumerable "own" properties of child objects are also recursively evaluated by the following rules.
Comparison details#
- Primitive values are compared with the Abstract Equality Comparison
(
==
). - Type tags of objects should be the same.
- Only enumerable "own" properties are considered.
Error
names and messages are always compared, even if these are not enumerable properties.- Object wrappers are compared both as objects and unwrapped values.
Object
properties are compared unordered.Map
keys andSet
items are compared unordered.- Recursion stops when both sides differ or both sides encounter a circular reference.
- Implementation does not test the
[[Prototype]]
of objects. Symbol
properties are not compared.WeakMap
andWeakSet
comparison does not rely on their values.
The following example does not throw an AssertionError
because the
primitives are considered equal by the Abstract Equality Comparison
( ==
).
// WARNING: This does not throw an AssertionError!
assert.deepEqual('+00000000', false);
"Deep" equality means that the enumerable "own" properties of child objects are evaluated also:
const assert = require('assert');
const obj1 = {
a: {
b: 1
}
};
const obj2 = {
a: {
b: 2
}
};
const obj3 = {
a: {
b: 1
}
};
const obj4 = Object.create(obj1);
assert.deepEqual(obj1, obj1);
// OK
// Values of b are different:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }
assert.deepEqual(obj1, obj3);
// OK
// Prototypes are ignored:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
If the values are not equal, an AssertionError
is thrown with a message
property set equal to the value of the message
parameter. If the message
parameter is undefined, a default error message is assigned. If the message
parameter is an instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.deepStrictEqual(actual, expected[, message])
#
Tests for deep equality between the actual
and expected
parameters.
"Deep" equality means that the enumerable "own" properties of child objects
are recursively evaluated also by the following rules.
Comparison details#
- Primitive values are compared using the SameValue Comparison, used by
Object.is()
. - Type tags of objects should be the same.
[[Prototype]]
of objects are compared using the Strict Equality Comparison.- Only enumerable "own" properties are considered.
Error
names and messages are always compared, even if these are not enumerable properties.- Enumerable own
Symbol
properties are compared as well. - Object wrappers are compared both as objects and unwrapped values.
Object
properties are compared unordered.Map
keys andSet
items are compared unordered.- Recursion stops when both sides differ or both sides encounter a circular reference.
WeakMap
andWeakSet
comparison does not rely on their values. See below for further details.
const assert = require('assert').strict;
// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// {
// + a: 1
// - a: '1'
// }
// The following objects don't have own properties
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);
// Different [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}
// Different type tags:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}
assert.deepStrictEqual(NaN, NaN);
// OK, because of the SameValue comparison
// Different unwrapped numbers:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]
assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK because the object and the string are identical when unwrapped.
assert.deepStrictEqual(-0, -0);
// OK
// Different zeros using the SameValue Comparison:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0
const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK, because it is the same symbol on both objects.
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
// [Symbol()]: 1
// }
const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap([[{}, {}]]);
const weakMap3 = new WeakMap();
weakMap3.unequal = true;
assert.deepStrictEqual(weakMap1, weakMap2);
// OK, because it is impossible to compare the entries
// Fails because weakMap3 has a property that weakMap1 does not contain:
assert.deepStrictEqual(weakMap1, weakMap3);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// WeakMap {
// + [items unknown]
// - [items unknown],
// - unequal: true
// }
If the values are not equal, an AssertionError
is thrown with a message
property set equal to the value of the message
parameter. If the message
parameter is undefined, a default error message is assigned. If the message
parameter is an instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.doesNotMatch(string, regexp[, message])
#
Expects the string
input not to match the regular expression.
This feature is currently experimental and the name might change or it might be completely removed again.
const assert = require('assert').strict;
assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...
assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.
assert.doesNotMatch('I will pass', /different/);
// OK
If the values do match, or if the string
argument is of another type than
string
, an AssertionError
is thrown with a message
property set equal
to the value of the message
parameter. If the message
parameter is
undefined, a default error message is assigned. If the message
parameter is an
instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.doesNotReject(asyncFn[, error][, message])
#
asyncFn
<Function> | <Promise>error
<RegExp> | <Function>message
<string>
Awaits the asyncFn
promise or, if asyncFn
is a function, immediately
calls the function and awaits the returned promise to complete. It will then
check that the promise is not rejected.
If asyncFn
is a function and it throws an error synchronously,
assert.doesNotReject()
will return a rejected Promise
with that error. If
the function does not return a promise, assert.doesNotReject()
will return a
rejected Promise
with an ERR_INVALID_RETURN_VALUE
error. In both cases
the error handler is skipped.
Using assert.doesNotReject()
is actually not useful because there is little
benefit in catching a rejection and then rejecting it again. Instead, consider
adding a comment next to the specific code path that should not reject and keep
error messages as expressive as possible.
If specified, error
can be a Class
, RegExp
or a validation
function. See assert.throws()
for more details.
Besides the async nature to await the completion behaves identically to
assert.doesNotThrow()
.
(async () => {
await assert.doesNotReject(
async () => {
throw new TypeError('Wrong value');
},
SyntaxError
);
})();
assert.doesNotReject(Promise.reject(new TypeError('Wrong value')))
.then(() => {
// ...
});
assert.doesNotThrow(fn[, error][, message])
#
fn
<Function>error
<RegExp> | <Function>message
<string>
Asserts that the function fn
does not throw an error.
Using assert.doesNotThrow()
is actually not useful because there
is no benefit in catching an error and then rethrowing it. Instead, consider
adding a comment next to the specific code path that should not throw and keep
error messages as expressive as possible.
When assert.doesNotThrow()
is called, it will immediately call the fn
function.
If an error is thrown and it is the same type as that specified by the error
parameter, then an AssertionError
is thrown. If the error is of a
different type, or if the error
parameter is undefined, the error is
propagated back to the caller.
If specified, error
can be a Class
, RegExp
or a validation
function. See assert.throws()
for more details.
The following, for instance, will throw the TypeError
because there is no
matching error type in the assertion:
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
SyntaxError
);
However, the following will result in an AssertionError
with the message
'Got unwanted exception...':
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
TypeError
);
If an AssertionError
is thrown and a value is provided for the message
parameter, the value of message
will be appended to the AssertionError
message:
assert.doesNotThrow(
() => {
throw new TypeError('Wrong value');
},
/Wrong value/,
'Whoops'
);
// Throws: AssertionError: Got unwanted exception: Whoops
assert.equal(actual, expected[, message])
#
Strict assertion mode
An alias of assert.strictEqual()
.
Legacy assertion mode
assert.strictEqual()
instead.Tests shallow, coercive equality between the actual
and expected
parameters
using the Abstract Equality Comparison ( ==
).
const assert = require('assert');
assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
If the values are not equal, an AssertionError
is thrown with a message
property set equal to the value of the message
parameter. If the message
parameter is undefined, a default error message is assigned. If the message
parameter is an instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.fail([message])
#
Throws an AssertionError
with the provided error message or a default
error message. If the message
parameter is an instance of an Error
then
it will be thrown instead of the AssertionError
.
const assert = require('assert').strict;
assert.fail();
// AssertionError [ERR_ASSERTION]: Failed
assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom
assert.fail(new TypeError('need array'));
// TypeError: need array
Using assert.fail()
with more than two arguments is possible but deprecated.
See below for further details.
assert.fail(actual, expected[, message[, operator[, stackStartFn]]])
#
assert.fail([message])
or other assert
functions instead.actual
<any>expected
<any>message
<string> | <Error>operator
<string> Default:'!='
stackStartFn
<Function> Default:assert.fail
If message
is falsy, the error message is set as the values of actual
and
expected
separated by the provided operator
. If just the two actual
and
expected
arguments are provided, operator
will default to '!='
. If
message
is provided as third argument it will be used as the error message and
the other arguments will be stored as properties on the thrown object. If
stackStartFn
is provided, all stack frames above that function will be
removed from stacktrace (see Error.captureStackTrace
). If no arguments are
given, the default message Failed
will be used.
const assert = require('assert').strict;
assert.fail('a', 'b');
// AssertionError [ERR_ASSERTION]: 'a' != 'b'
assert.fail(1, 2, undefined, '>');
// AssertionError [ERR_ASSERTION]: 1 > 2
assert.fail(1, 2, 'fail');
// AssertionError [ERR_ASSERTION]: fail
assert.fail(1, 2, 'whoops', '>');
// AssertionError [ERR_ASSERTION]: whoops
assert.fail(1, 2, new TypeError('need array'));
// TypeError: need array
In the last three cases actual
, expected
, and operator
have no
influence on the error message.
Example use of stackStartFn
for truncating the exception's stacktrace:
function suppressFrame() {
assert.fail('a', 'b', undefined, '!==', suppressFrame);
}
suppressFrame();
// AssertionError [ERR_ASSERTION]: 'a' !== 'b'
// at repl:1:1
// at ContextifyScript.Script.runInThisContext (vm.js:44:33)
// ...
assert.ifError(value)
#
value
<any>
Throws value
if value
is not undefined
or null
. This is useful when
testing the error
argument in callbacks. The stack trace contains all frames
from the error passed to ifError()
including the potential new frames for
ifError()
itself.
const assert = require('assert').strict;
assert.ifError(null);
// OK
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error
// Create some random error frames.
let err;
(function errorFrame() {
err = new Error('test error');
})();
(function ifErrorFrame() {
assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
// at ifErrorFrame
// at errorFrame
assert.match(string, regexp[, message])
#
Expects the string
input to match the regular expression.
This feature is currently experimental and the name might change or it might be completely removed again.
const assert = require('assert').strict;
assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...
assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.
assert.match('I will pass', /pass/);
// OK
If the values do not match, or if the string
argument is of another type than
string
, an AssertionError
is thrown with a message
property set equal
to the value of the message
parameter. If the message
parameter is
undefined, a default error message is assigned. If the message
parameter is an
instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.notDeepEqual(actual, expected[, message])
#
Strict assertion mode
An alias of assert.notDeepStrictEqual()
.
Legacy assertion mode
assert.notDeepStrictEqual()
instead.Tests for any deep inequality. Opposite of assert.deepEqual()
.
const assert = require('assert');
const obj1 = {
a: {
b: 1
}
};
const obj2 = {
a: {
b: 2
}
};
const obj3 = {
a: {
b: 1
}
};
const obj4 = Object.create(obj1);
assert.notDeepEqual(obj1, obj1);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }
assert.notDeepEqual(obj1, obj2);
// OK
assert.notDeepEqual(obj1, obj3);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }
assert.notDeepEqual(obj1, obj4);
// OK
If the values are deeply equal, an AssertionError
is thrown with a
message
property set equal to the value of the message
parameter. If the
message
parameter is undefined, a default error message is assigned. If the
message
parameter is an instance of an Error
then it will be thrown
instead of the AssertionError
.
assert.notDeepStrictEqual(actual, expected[, message])
#
Tests for deep strict inequality. Opposite of assert.deepStrictEqual()
.
const assert = require('assert').strict;
assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
If the values are deeply and strictly equal, an AssertionError
is thrown
with a message
property set equal to the value of the message
parameter. If
the message
parameter is undefined, a default error message is assigned. If
the message
parameter is an instance of an Error
then it will be thrown
instead of the AssertionError
.
assert.notEqual(actual, expected[, message])
#
Strict assertion mode
An alias of assert.notStrictEqual()
.
Legacy assertion mode
assert.notStrictEqual()
instead.Tests shallow, coercive inequality with the Abstract Equality Comparison
( !=
).
const assert = require('assert');
assert.notEqual(1, 2);
// OK
assert.notEqual(1, 1);
// AssertionError: 1 != 1
assert.notEqual(1, '1');
// AssertionError: 1 != '1'
If the values are equal, an AssertionError
is thrown with a message
property set equal to the value of the message
parameter. If the message
parameter is undefined, a default error message is assigned. If the message
parameter is an instance of an Error
then it will be thrown instead of the
AssertionError
.
assert.notStrictEqual(actual, expected[, message])
#
Tests strict inequality between the actual
and expected
parameters as
determined by the SameValue Comparison.
const assert = require('assert').strict;
assert.notStrictEqual(1, 2);
// OK
assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1
assert.notStrictEqual(1, '1');
// OK
If the values are strictly equal, an AssertionError
is thrown with a
message
property set equal to the value of the message
parameter. If the
message
parameter is undefined, a default error message is assigned. If the
message
parameter is an instance of an Error
then it will be thrown
instead of the AssertionError
.
assert.ok(value[, message])
#
Tests if value
is truthy. It is equivalent to
assert.equal(!!value, true, message)
.
If value
is not truthy, an AssertionError
is thrown with a message
property set equal to the value of the message
parameter. If the message
parameter is undefined
, a default error message is assigned. If the message
parameter is an instance of an Error
then it will be thrown instead of the
AssertionError
.
If no arguments are passed in at all message
will be set to the string:
'No value argument passed to `assert.ok()`'
.
Be aware that in the repl
the error message will be different to the one
thrown in a file! See below for further details.
const assert = require('assert').strict;
assert.ok(true);
// OK
assert.ok(1);
// OK
assert.ok();
// AssertionError: No value argument passed to `assert.ok()`
assert.ok(false, 'it\'s false');
// AssertionError: it's false
// In the repl:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true
// In a file (e.g. test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(typeof 123 === 'string')
assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(false)
assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(0)
// Using `assert()` works the same:
assert(0);
// AssertionError: The expression evaluated to a falsy value:
//
// assert(0)
assert.rejects(asyncFn[, error][, message])
#
asyncFn
<Function> | <Promise>error
<RegExp> | <Function> | <Object> | <Error>message
<string>
Awaits the asyncFn
promise or, if asyncFn
is a function, immediately
calls the function and awaits the returned promise to complete. It will then
check that the promise is rejected.
If asyncFn
is a function and it throws an error synchronously,
assert.rejects()
will return a rejected Promise
with that error. If the
function does not return a promise, assert.rejects()
will return a rejected
Promise
with an ERR_INVALID_RETURN_VALUE
error. In both cases the error
handler is skipped.
Besides the async nature to await the completion behaves identically to
assert.throws()
.
If specified, error
can be a Class
, RegExp
, a validation function,
an object where each property will be tested for, or an instance of error where
each property will be tested for including the non-enumerable message
and
name
properties.
If specified, message
will be the message provided by the AssertionError
if the asyncFn
fails to reject.
(async () => {
await assert.rejects(
async () => {
throw new TypeError('Wrong value');
},
{
name: 'TypeError',
message: 'Wrong value'
}
);
})();
(async () => {
await assert.rejects(
async () => {
throw new TypeError('Wrong value');
},
(err) => {
assert.strictEqual(err.name, 'TypeError');
assert.strictEqual(err.message, 'Wrong value');
return true;
}
);
})();
assert.rejects(
Promise.reject(new Error('Wrong value')),
Error
).then(() => {
// ...
});
error
cannot be a string. If a string is provided as the second
argument, then error
is assumed to be omitted and the string will be used for
message
instead. This can lead to easy-to-miss mistakes. Please read the
example in assert.throws()
carefully if using a string as the second
argument gets considered.
assert.strictEqual(actual, expected[, message])
#
Tests strict equality between the actual
and expected
parameters as
determined by the SameValue Comparison.
const assert = require('assert').strict;
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
// ^
const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
If the values are not strictly equal, an AssertionError
is thrown with a
message
property set equal to the value of the message
parameter. If the
message
parameter is undefined, a default error message is assigned. If the
message
parameter is an instance of an Error
then it will be thrown
instead of the AssertionError
.
assert.throws(fn[, error][, message])
#
fn
<Function>error
<RegExp> | <Function> | <Object> | <Error>message
<string>
Expects the function fn
to throw an error.
If specified, error
can be a Class
, RegExp
, a validation function,
a validation object where each property will be tested for strict deep equality,
or an instance of error where each property will be tested for strict deep
equality including the non-enumerable message
and name
properties. When
using an object, it is also possible to use a regular expression, when
validating against a string property. See below for examples.
If specified, message
will be appended to the message provided by the
AssertionError
if the fn
call fails to throw or in case the error validation
fails.
Custom validation object/error instance:
const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
nested: true,
baz: 'text'
};
err.reg = /abc/i;
assert.throws(
() => {
throw err;
},
{
name: 'TypeError',
message: 'Wrong value',
info: {
nested: true,
baz: 'text'
}
// Only properties on the validation object will be tested for.
// Using nested objects requires all properties to be present. Otherwise
// the validation is going to fail.
}
);
// Using regular expressions to validate error properties:
assert.throws(
() => {
throw err;
},
{
// The `name` and `message` properties are strings and using regular
// expressions on those will match against the string. If they fail, an
// error is thrown.
name: /^TypeError$/,
message: /Wrong/,
foo: 'bar',
info: {
nested: true,
// It is not possible to use regular expressions for nested properties!
baz: 'text'
},
// The `reg` property contains a regular expression and only if the
// validation object contains an identical regular expression, it is going
// to pass.
reg: /abc/i
}
);
// Fails due to the different `message` and `name` properties:
assert.throws(
() => {
const otherErr = new Error('Not found');
// Copy all enumerable properties from `err` to `otherErr`.
for (const [key, value] of Object.entries(err)) {
otherErr[key] = value;
}
throw otherErr;
},
// The error's `message` and `name` properties will also be checked when using
// an error as validation object.
err
);
Validate instanceof using constructor:
assert.throws(
() => {
throw new Error('Wrong value');
},
Error
);
Validate error message using RegExp
:
Using a regular expression runs .toString
on the error object, and will
therefore also include the error name.
assert.throws(
() => {
throw new Error('Wrong value');
},
/^Error: Wrong value$/
);
Custom error validation:
The function must return true
to indicate all internal validations passed.
It will otherwise fail with an AssertionError
.
assert.throws(
() => {
throw new Error('Wrong value');
},
(err) => {
assert(err instanceof Error);
assert(/value/.test(err));
// Avoid returning anything from validation functions besides `true`.
// Otherwise, it's not clear what part of the validation failed. Instead,
// throw an error about the specific validation that failed (as done in this
// example) and add as much helpful debugging information to that error as
// possible.
return true;
},
'unexpected error'
);
error
cannot be a string. If a string is provided as the second
argument, then error
is assumed to be omitted and the string will be used for
message
instead. This can lead to easy-to-miss mistakes. Using the same
message as the thrown error message is going to result in an
ERR_AMBIGUOUS_ARGUMENT
error. Please read the example below carefully if using
a string as the second argument gets considered:
function throwingFirst() {
throw new Error('First');
}
function throwingSecond() {
throw new Error('Second');
}
function notThrowing() {}
// The second argument is a string and the input function threw an Error.
// The first case will not throw as it does not match for the error message
// thrown by the input function!
assert.throws(throwingFirst, 'Second');
// In the next example the message has no benefit over the message from the
// error and since it is not clear if the user intended to actually match
// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]
// The string is only used (as message) in case the function does not throw:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second
// If it was intended to match for the error message do this instead:
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);
// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]
Due to the confusing error-prone notation, avoid a string as the second argument.
Async hooks#
Source Code: lib/async_hooks.js
The async_hooks
module provides an API to track asynchronous resources. It
can be accessed using:
const async_hooks = require('async_hooks');
Terminology#
An asynchronous resource represents an object with an associated callback.
This callback may be called multiple times, for example, the 'connection'
event in net.createServer()
, or just a single time like in fs.open()
.
A resource can also be closed before the callback is called. AsyncHook
does
not explicitly distinguish between these different cases but will represent them
as the abstract concept that is a resource.
If Worker
s are used, each thread has an independent async_hooks
interface, and each thread will use a new set of async IDs.
Public API#
Overview#
Following is a simple overview of the public API.
const async_hooks = require('async_hooks');
// Return the ID of the current execution context.
const eid = async_hooks.executionAsyncId();
// Return the ID of the handle responsible for triggering the callback of the
// current execution scope to call.
const tid = async_hooks.triggerAsyncId();
// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook =
async_hooks.createHook({ init, before, after, destroy, promiseResolve });
// Allow callbacks of this AsyncHook instance to call. This is not an implicit
// action after running the constructor, and must be explicitly run to begin
// executing callbacks.
asyncHook.enable();
// Disable listening for new asynchronous events.
asyncHook.disable();
//
// The following are the callbacks that can be passed to createHook().
//
// init is called during object construction. The resource may not have
// completed construction when this callback runs, therefore all fields of the
// resource referenced by "asyncId" may not have been populated.
function init(asyncId, type, triggerAsyncId, resource) { }
// Before is called just before the resource's callback is called. It can be
// called 0-N times for handles (e.g. TCPWrap), and will be called exactly 1
// time for requests (e.g. FSReqCallback).
function before(asyncId) { }
// After is called just after the resource's callback has finished.
function after(asyncId) { }
// Destroy is called when the resource is destroyed.
function destroy(asyncId) { }
// promiseResolve is called only for promise resources, when the
// `resolve` function passed to the `Promise` constructor is invoked
// (either directly or through other means of resolving a promise).
function promiseResolve(asyncId) { }
async_hooks.createHook(callbacks)
#
callbacks
<Object> The Hook Callbacks to registerinit
<Function> Theinit
callback.before
<Function> Thebefore
callback.after
<Function> Theafter
callback.destroy
<Function> Thedestroy
callback.promiseResolve
<Function> ThepromiseResolve
callback.
- Returns: <AsyncHook> Instance used for disabling and enabling hooks
Registers functions to be called for different lifetime events of each async operation.
The callbacks init()
/before()
/after()
/destroy()
are called for the
respective asynchronous event during a resource's lifetime.
All callbacks are optional. For example, if only resource cleanup needs to
be tracked, then only the destroy
callback needs to be passed. The
specifics of all functions that can be passed to callbacks
is in the
Hook Callbacks section.
const async_hooks = require('async_hooks');
const asyncHook = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) { },
destroy(asyncId) { }
});
The callbacks will be inherited via the prototype chain:
class MyAsyncCallbacks {
init(asyncId, type, triggerAsyncId, resource) { }
destroy(asyncId) {}
}
class MyAddedCallbacks extends MyAsyncCallbacks {
before(asyncId) { }
after(asyncId) { }
}
const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
Error handling#
If any AsyncHook
callbacks throw, the application will print the stack trace
and exit. The exit path does follow that of an uncaught exception, but
all 'uncaughtException'
listeners are removed, thus forcing the process to
exit. The 'exit'
callbacks will still be called unless the application is run
with --abort-on-uncaught-exception
, in which case a stack trace will be
printed and the application exits, leaving a core file.
The reason for this error handling behavior is that these callbacks are running at potentially volatile points in an object's lifetime, for example during class construction and destruction. Because of this, it is deemed necessary to bring down the process quickly in order to prevent an unintentional abort in the future. This is subject to change in the future if a comprehensive analysis is performed to ensure an exception can follow the normal control flow without unintentional side effects.
Printing in AsyncHooks callbacks#
Because printing to the console is an asynchronous operation, console.log()
will cause the AsyncHooks callbacks to be called. Using console.log()
or
similar asynchronous operations inside an AsyncHooks callback function will thus
cause an infinite recursion. An easy solution to this when debugging is to use a
synchronous logging operation such as fs.writeFileSync(file, msg, flag)
.
This will print to the file and will not invoke AsyncHooks recursively because
it is synchronous.
const fs = require('fs');
const util = require('util');
function debug(...args) {
// Use a function like this one when debugging inside an AsyncHooks callback
fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' });
}
If an asynchronous operation is needed for logging, it is possible to keep track of what caused the asynchronous operation using the information provided by AsyncHooks itself. The logging should then be skipped when it was the logging itself that caused AsyncHooks callback to call. By doing this the otherwise infinite recursion is broken.
Class: AsyncHook
#
The class AsyncHook
exposes an interface for tracking lifetime events
of asynchronous operations.
asyncHook.enable()
#
- Returns: <AsyncHook> A reference to
asyncHook
.
Enable the callbacks for a given AsyncHook
instance. If no callbacks are
provided enabling is a noop.
The AsyncHook
instance is disabled by default. If the AsyncHook
instance
should be enabled immediately after creation, the following pattern can be used.
const async_hooks = require('async_hooks');
const hook = async_hooks.createHook(callbacks).enable();
asyncHook.disable()
#
- Returns: <AsyncHook> A reference to
asyncHook
.
Disable the callbacks for a given AsyncHook
instance from the global pool of
AsyncHook
callbacks to be executed. Once a hook has been disabled it will not
be called again until enabled.
For API consistency disable()
also returns the AsyncHook
instance.
Hook callbacks#
Key events in the lifetime of asynchronous events have been categorized into four areas: instantiation, before/after the callback is called, and when the instance is destroyed.
init(asyncId, type, triggerAsyncId, resource)
#
asyncId
<number> A unique ID for the async resource.type
<string> The type of the async resource.triggerAsyncId
<number> The unique ID of the async resource in whose execution context this async resource was created.resource
<Object> Reference to the resource representing the async operation, needs to be released during destroy.
Called when a class is constructed that has the possibility to emit an
asynchronous event. This does not mean the instance must call
before
/after
before destroy
is called, only that the possibility
exists.
This behavior can be observed by doing something like opening a resource then closing it before the resource can be used. The following snippet demonstrates this.
require('net').createServer().listen(function() { this.close(); });
// OR
clearTimeout(setTimeout(() => {}, 10));
Every new resource is assigned an ID that is unique within the scope of the current Node.js instance.
type
#
The type
is a string identifying the type of resource that caused
init
to be called. Generally, it will correspond to the name of the
resource's constructor.
FSEVENTWRAP, FSREQCALLBACK, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPINCOMINGMESSAGE,
HTTPCLIENTREQUEST, JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP,
SHUTDOWNWRAP, SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVERWRAP, TCPWRAP,
TTYWRAP, UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST,
RANDOMBYTESREQUEST, TLSWRAP, Microtask, Timeout, Immediate, TickObject
There is also the PROMISE
resource type, which is used to track Promise
instances and asynchronous work scheduled by them.
Users are able to define their own type
when using the public embedder API.
It is possible to have type name collisions. Embedders are encouraged to use unique prefixes, such as the npm package name, to prevent collisions when listening to the hooks.
triggerAsyncId
#
triggerAsyncId
is the asyncId
of the resource that caused (or "triggered")
the new resource to initialize and that caused init
to call. This is different
from async_hooks.executionAsyncId()
that only shows when a resource was
created, while triggerAsyncId
shows why a resource was created.
The following is a simple demonstration of triggerAsyncId
:
async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
const eid = async_hooks.executionAsyncId();
fs.writeSync(
process.stdout.fd,
`${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
}
}).enable();
require('net').createServer((conn) => {}).listen(8080);
Output when hitting the server with nc localhost 8080
:
TCPSERVERWRAP(5): trigger: 1 execution: 1
TCPWRAP(7): trigger: 5 execution: 0
The TCPSERVERWRAP
is the server which receives the connections.
The TCPWRAP
is the new connection from the client. When a new
connection is made, the TCPWrap
instance is immediately constructed. This
happens outside of any JavaScript stack. (An executionAsyncId()
of 0
means
that it is being executed from C++ with no JavaScript stack above it.) With only
that information, it would be impossible to link resources together in
terms of what caused them to be created, so triggerAsyncId
is given the task
of propagating what resource is responsible for the new resource's existence.
resource
#
resource
is an object that represents the actual async resource that has
been initialized. This can contain useful information that can vary based on
the value of type
. For instance, for the GETADDRINFOREQWRAP
resource type,
resource
provides the host name used when looking up the IP address for the
host in net.Server.listen()
. The API for accessing this information is
not supported, but using the Embedder API, users can provide
and document their own resource objects. For example, such a resource object
could contain the SQL query being executed.
In the case of Promises, the resource
object will have an
isChainedPromise
property, set to true
if the promise has a parent promise,
and false
otherwise. For example, in the case of b = a.then(handler)
, a
is
considered a parent Promise
of b
. Here, b
is considered a chained promise.
In some cases the resource object is reused for performance reasons, it is
thus not safe to use it as a key in a WeakMap
or add properties to it.
Asynchronous context example#
The following is an example with additional information about the calls to
init
between the before
and after
calls, specifically what the
callback to listen()
will look like. The output formatting is slightly more
elaborate to make calling context easier to see.
let indent = 0;
async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
const eid = async_hooks.executionAsyncId();
const indentStr = ' '.repeat(indent);
fs.writeSync(
process.stdout.fd,
`${indentStr}${type}(${asyncId}):` +
` trigger: ${triggerAsyncId} execution: ${eid}\n`);
},
before(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(process.stdout.fd, `${indentStr}before: ${asyncId}\n`);
indent += 2;
},
after(asyncId) {
indent -= 2;
const indentStr = ' '.repeat(indent);
fs.writeSync(process.stdout.fd, `${indentStr}after: ${asyncId}\n`);
},
destroy(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(process.stdout.fd, `${indentStr}destroy: ${asyncId}\n`);
},
}).enable();
require('net').createServer(() => {}).listen(8080, () => {
// Let's wait 10ms before logging the server started.
setTimeout(() => {
console.log('>>>', async_hooks.executionAsyncId());
}, 10);
});
Output from only starting the server:
TCPSERVERWRAP(5): trigger: 1 execution: 1
TickObject(6): trigger: 5 execution: 1
before: 6
Timeout(7): trigger: 6 execution: 6
after: 6
destroy: 6
before: 7
>>> 7
TickObject(8): trigger: 7 execution: 7
after: 7
before: 8
after: 8
As illustrated in the example, executionAsyncId()
and execution
each specify
the value of the current execution context; which is delineated by calls to
before
and after
.
Only using execution
to graph resource allocation results in the following:
root(1)
^
|
TickObject(6)
^
|
Timeout(7)
The TCPSERVERWRAP
is not part of this graph, even though it was the reason for
console.log()
being called. This is because binding to a port without a host
name is a synchronous operation, but to maintain a completely asynchronous
API the user's callback is placed in a process.nextTick()
. Which is why
TickObject
is present in the output and is a 'parent' for .listen()
callback.
The graph only shows when a resource was created, not why, so to track
the why use triggerAsyncId
. Which can be represented with the following
graph:
bootstrap(1)
|
˅
TCPSERVERWRAP(5)
|
˅
TickObject(6)
|
˅
Timeout(7)
before(asyncId)
#
asyncId
<number>
When an asynchronous operation is initiated (such as a TCP server receiving a
new connection) or completes (such as writing data to disk) a callback is
called to notify the user. The before
callback is called just before said
callback is executed. asyncId
is the unique identifier assigned to the
resource about to execute the callback.
The before
callback will be called 0 to N times. The before
callback
will typically be called 0 times if the asynchronous operation was cancelled
or, for example, if no connections are received by a TCP server. Persistent
asynchronous resources like a TCP server will typically call the before
callback multiple times, while other operations like fs.open()
will call
it only once.
after(asyncId)
#
asyncId
<number>
Called immediately after the callback specified in before
is completed.
If an uncaught exception occurs during execution of the callback, then after
will run after the 'uncaughtException'
event is emitted or a domain
's
handler runs.
destroy(asyncId)
#
asyncId
<number>
Called after the resource corresponding to asyncId
is destroyed. It is also
called asynchronously from the embedder API emitDestroy()
.
Some resources depend on garbage collection for cleanup, so if a reference is
made to the resource
object passed to init
it is possible that destroy
will never be called, causing a memory leak in the application. If the resource
does not depend on garbage collection, then this will not be an issue.
promiseResolve(asyncId)
#
asyncId
<number>
Called when the resolve
function passed to the Promise
constructor is
invoked (either directly or through other means of resolving a promise).
resolve()
does not do any observable synchronous work.
The Promise
is not necessarily fulfilled or rejected at this point if the
Promise
was resolved by assuming the state of another Promise
.
new Promise((resolve) => resolve(true)).then((a) => {});
calls the following callbacks:
init for PROMISE with id 5, trigger id: 1
promise resolve 5 # corresponds to resolve(true)
init for PROMISE with id 6, trigger id: 5 # the Promise returned by then()
before 6 # the then() callback is entered
promise resolve 6 # the then() callback resolves the promise by returning
after 6
async_hooks.executionAsyncResource()
#
- Returns: <Object> The resource representing the current execution. Useful to store data within the resource.
Resource objects returned by executionAsyncResource()
are most often internal
Node.js handle objects with undocumented APIs. Using any functions or properties
on the object is likely to crash your application and should be avoided.
Using executionAsyncResource()
in the top-level execution context will
return an empty object as there is no handle or request object to use,
but having an object representing the top-level can be helpful.
const { open } = require('fs');
const { executionAsyncId, executionAsyncResource } = require('async_hooks');
console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
open(__filename, 'r', (err, fd) => {
console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
});
This can be used to implement continuation local storage without the
use of a tracking Map
to store the metadata:
const { createServer } = require('http');
const {
executionAsyncId,
executionAsyncResource,
createHook
} = require('async_hooks');
const sym = Symbol('state'); // Private symbol to avoid pollution
createHook({
init(asyncId, type, triggerAsyncId, resource) {
const cr = executionAsyncResource();
if (cr) {
resource[sym] = cr[sym];
}
}
}).enable();
const server = createServer((req, res) => {
executionAsyncResource()[sym] = { state: req.url };
setTimeout(function() {
res.end(JSON.stringify(executionAsyncResource()[sym]));
}, 100);
}).listen(3000);
async_hooks.executionAsyncId()
#
- Returns: <number> The
asyncId
of the current execution context. Useful to track when something calls.
const async_hooks = require('async_hooks');
console.log(async_hooks.executionAsyncId()); // 1 - bootstrap
fs.open(path, 'r', (err, fd) => {
console.log(async_hooks.executionAsyncId()); // 6 - open()
});
The ID returned from executionAsyncId()
is related to execution timing, not
causality (which is covered by triggerAsyncId()
):
const server = net.createServer((conn) => {
// Returns the ID of the server, not of the new connection, because the
// callback runs in the execution scope of the server's MakeCallback().
async_hooks.executionAsyncId();
}).listen(port, () => {
// Returns the ID of a TickObject (i.e. process.nextTick()) because all
// callbacks passed to .listen() are wrapped in a nextTick().
async_hooks.executionAsyncId();
});
Promise contexts may not get precise executionAsyncIds
by default.
See the section on promise execution tracking.
async_hooks.triggerAsyncId()
#
- Returns: <number> The ID of the resource responsible for calling the callback that is currently being executed.
const server = net.createServer((conn) => {
// The resource that caused (or triggered) this callback to be called
// was that of the new connection. Thus the return value of triggerAsyncId()
// is the asyncId of "conn".
async_hooks.triggerAsyncId();
}).listen(port, () => {
// Even though all callbacks passed to .listen() are wrapped in a nextTick()
// the callback itself exists because the call to the server's .listen()
// was made. So the return value would be the ID of the server.
async_hooks.triggerAsyncId();
});
Promise contexts may not get valid triggerAsyncId
s by default. See
the section on promise execution tracking.
Promise execution tracking#
By default, promise executions are not assigned asyncId
s due to the relatively
expensive nature of the promise introspection API provided by
V8. This means that programs using promises or async
/await
will not get
correct execution and trigger ids for promise callback contexts by default.
const ah = require('async_hooks');
Promise.resolve(1729).then(() => {
console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0
Observe that the then()
callback claims to have executed in the context of the
outer scope even though there was an asynchronous hop involved. Also,
the triggerAsyncId
value is 0
, which means that we are missing context about
the resource that caused (triggered) the then()
callback to be executed.
Installing async hooks via async_hooks.createHook
enables promise execution
tracking:
const ah = require('async_hooks');
ah.createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6
In this example, adding any actual hook function enabled the tracking of
promises. There are two promises in the example above; the promise created by
Promise.resolve()
and the promise returned by the call to then()
. In the
example above, the first promise got the asyncId
6
and the latter got
asyncId
7
. During the execution of the then()
callback, we are executing
in the context of promise with asyncId
7
. This promise was triggered by
async resource 6
.
Another subtlety with promises is that before
and after
callbacks are run
only on chained promises. That means promises not created by then()
/catch()
will not have the before
and after
callbacks fired on them. For more details
see the details of the V8 PromiseHooks API.
JavaScript embedder API#
Library developers that handle their own asynchronous resources performing tasks
like I/O, connection pooling, or managing callback queues may use the
AsyncResource
JavaScript API so that all the appropriate callbacks are called.
Class: AsyncResource
#
The class AsyncResource
is designed to be extended by the embedder's async
resources. Using this, users can easily trigger the lifetime events of their
own resources.
The init
hook will trigger when an AsyncResource
is instantiated.
The following is an overview of the AsyncResource
API.
const { AsyncResource, executionAsyncId } = require('async_hooks');
// AsyncResource() is meant to be extended. Instantiating a
// new AsyncResource() also triggers init. If triggerAsyncId is omitted then
// async_hook.executionAsyncId() is used.
const asyncResource = new AsyncResource(
type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false }
);
// Run a function in the execution context of the resource. This will
// * establish the context of the resource
// * trigger the AsyncHooks before callbacks
// * call the provided function `fn` with the supplied arguments
// * trigger the AsyncHooks after callbacks
// * restore the original execution context
asyncResource.runInAsyncScope(fn, thisArg, ...args);
// Call AsyncHooks destroy callbacks.
asyncResource.emitDestroy();
// Return the unique ID assigned to the AsyncResource instance.
asyncResource.asyncId();
// Return the trigger ID for the AsyncResource instance.
asyncResource.triggerAsyncId();
new AsyncResource(type[, options])
#
type
<string> The type of async event.options
<Object>triggerAsyncId
<number> The ID of the execution context that created this async event. Default:executionAsyncId()
.requireManualDestroy
<boolean> If set totrue
, disablesemitDestroy
when the object is garbage collected. This usually does not need to be set (even ifemitDestroy
is called manually), unless the resource'sasyncId
is retrieved and the sensitive API'semitDestroy
is called with it. When set tofalse
, theemitDestroy
call on garbage collection will only take place if there is at least one activedestroy
hook. Default:false
.
Example usage:
class DBQuery extends AsyncResource {
constructor(db) {
super('DBQuery');
this.db = db;
}
getInfo(query, callback) {
this.db.get(query, (err, data) => {
this.runInAsyncScope(callback, null, err, data);
});
}
close() {
this.db = null;
this.emitDestroy();
}
}
Static method: AsyncResource.bind(fn[, type])
#
fn
<Function> The function to bind to the current execution context.type
<string> An optional name to associate with the underlyingAsyncResource
.
Binds the given function to the current execution context.
The returned function will have an asyncResource
property referencing
the AsyncResource
to which the function is bound.
asyncResource.bind(fn)
#
fn
<Function> The function to bind to the currentAsyncResource
.
Binds the given function to execute to this AsyncResource
's scope.
The returned function will have an asyncResource
property referencing
the AsyncResource
to which the function is bound.
asyncResource.runInAsyncScope(fn[, thisArg, ...args])
#
fn
<Function> The function to call in the execution context of this async resource.thisArg
<any> The receiver to be used for the function call....args
<any> Optional arguments to pass to the function.
Call the provided function with the provided arguments in the execution context of the async resource. This will establish the context, trigger the AsyncHooks before callbacks, call the function, trigger the AsyncHooks after callbacks, and then restore the original execution context.
asyncResource.emitDestroy()
#
- Returns: <AsyncResource> A reference to
asyncResource
.
Call all destroy
hooks. This should only ever be called once. An error will
be thrown if it is called more than once. This must be manually called. If
the resource is left to be collected by the GC then the destroy
hooks will
never be called.
asyncResource.asyncId()
#
- Returns: <number> The unique
asyncId
assigned to the resource.
asyncResource.triggerAsyncId()
#
- Returns: <number> The same
triggerAsyncId
that is passed to theAsyncResource
constructor.
Using AsyncResource
for a Worker
thread pool#
The following example shows how to use the AsyncResource
class to properly
provide async tracking for a Worker
pool. Other resource pools, such as
database connection pools, can follow a similar model.
Assuming that the task is adding two numbers, using a file named
task_processor.js
with the following content:
const { parentPort } = require('worker_threads');
parentPort.on('message', (task) => {
parentPort.postMessage(task.a + task.b);
});
a Worker pool around it could use the following structure:
const { AsyncResource } = require('async_hooks');
const { EventEmitter } = require('events');
const path = require('path');
const { Worker } = require('worker_threads');
const kTaskInfo = Symbol('kTaskInfo');
const kWorkerFreedEvent = Symbol('kWorkerFreedEvent');
class WorkerPoolTaskInfo extends AsyncResource {
constructor(callback) {
super('WorkerPoolTaskInfo');
this.callback = callback;
}
done(err, result) {
this.runInAsyncScope(this.callback, null, err, result);
this.emitDestroy(); // `TaskInfo`s are used only once.
}
}
class WorkerPool extends EventEmitter {
constructor(numThreads) {
super();
this.numThreads = numThreads;
this.workers = [];
this.freeWorkers = [];
for (let i = 0; i < numThreads; i++)
this.addNewWorker();
}
addNewWorker() {
const worker = new Worker(path.resolve(__dirname, 'task_processor.js'));
worker.on('message', (result) => {
// In case of success: Call the callback that was passed to `runTask`,
// remove the `TaskInfo` associated with the Worker, and mark it as free
// again.
worker[kTaskInfo].done(null, result);
worker[kTaskInfo] = null;
this.freeWorkers.push(worker);
this.emit(kWorkerFreedEvent);
});
worker.on('error', (err) => {
// In case of an uncaught exception: Call the callback that was passed to
// `runTask` with the error.
if (worker[kTaskInfo])
worker[kTaskInfo].done(err, null);
else
this.emit('error', err);
// Remove the worker from the list and start a new Worker to replace the
// current one.
this.workers.splice(this.workers.indexOf(worker), 1);
this.addNewWorker();
});
this.workers.push(worker);
this.freeWorkers.push(worker);
this.emit(kWorkerFreedEvent);
}
runTask(task, callback) {
if (this.freeWorkers.length === 0) {
// No free threads, wait until a worker thread becomes free.
this.once(kWorkerFreedEvent, () => this.runTask(task, callback));
return;
}
const worker = this.freeWorkers.pop();
worker[kTaskInfo] = new WorkerPoolTaskInfo(callback);
worker.postMessage(task);
}
close() {
for (const worker of this.workers) worker.terminate();
}
}
module.exports = WorkerPool;
Without the explicit tracking added by the WorkerPoolTaskInfo
objects,
it would appear that the callbacks are associated with the individual Worker
objects. However, the creation of the Worker
s is not associated with the
creation of the tasks and does not provide information about when tasks
were scheduled.
This pool could be used as follows:
const WorkerPool = require('./worker_pool.js');
const os = require('os');
const pool = new WorkerPool(os.cpus().length);
let finished = 0;
for (let i = 0; i < 10; i++) {
pool.runTask({ a: 42, b: 100 }, (err, result) => {
console.log(i, err, result);
if (++finished === 10)
pool.close();
});
}
Integrating AsyncResource
with EventEmitter
#
Event listeners triggered by an EventEmitter
may be run in a different
execution context than the one that was active when eventEmitter.on()
was
called.
The following example shows how to use the AsyncResource
class to properly
associate an event listener with the correct execution context. The same
approach can be applied to a Stream
or a similar event-driven class.
const { createServer } = require('http');
const { AsyncResource, executionAsyncId } = require('async_hooks');
const server = createServer((req, res) => {
req.on('close', AsyncResource.bind(() => {
// Execution context is bound to the current outer scope.
}));
req.on('close', () => {
// Execution context is bound to the scope that caused 'close' to emit.
});
res.end();
}).listen(3000);
Class: AsyncLocalStorage
#
This class is used to create asynchronous state within callbacks and promise chains. It allows storing data throughout the lifetime of a web request or any other asynchronous duration. It is similar to thread-local storage in other languages.
The following example uses AsyncLocalStorage
to build a simple logger
that assigns IDs to incoming HTTP requests and includes them in messages
logged within each request.
const http = require('http');
const { AsyncLocalStorage } = require('async_hooks');
const asyncLocalStorage = new AsyncLocalStorage();
function logWithId(msg) {
const id = asyncLocalStorage.getStore();
console.log(`${id !== undefined ? id : '-'}:`, msg);
}
let idSeq = 0;
http.createServer((req, res) => {
asyncLocalStorage.run(idSeq++, () => {
logWithId('start');
// Imagine any chain of async operations here
setImmediate(() => {
logWithId('finish');
res.end();
});
});
}).listen(8080);
http.get('http://localhost:8080');
http.get('http://localhost:8080');
// Prints:
// 0: start
// 1: start
// 0: finish
// 1: finish
When having multiple instances of AsyncLocalStorage
, they are independent
from each other. It is safe to instantiate this class multiple times.
new AsyncLocalStorage()
#
Creates a new instance of AsyncLocalStorage
. Store is only provided within a
run
method call.
asyncLocalStorage.disable()
#
This method disables the instance of AsyncLocalStorage
. All subsequent calls
to asyncLocalStorage.getStore()
will return undefined
until
asyncLocalStorage.run()
is called again.
When calling asyncLocalStorage.disable()
, all current contexts linked to the
instance will be exited.
Calling asyncLocalStorage.disable()
is required before the
asyncLocalStorage
can be garbage collected. This does not apply to stores
provided by the asyncLocalStorage
, as those objects are garbage collected
along with the corresponding async resources.
This method is to be used when the asyncLocalStorage
is not in use anymore
in the current process.
asyncLocalStorage.getStore()
#
- Returns: <any>
This method returns the current store.
If this method is called outside of an asynchronous context initialized by
calling asyncLocalStorage.run
, it will return undefined
.
asyncLocalStorage.enterWith(store)
#
store
<any>
Calling asyncLocalStorage.enterWith(store)
will transition into the context
for the remainder of the current synchronous execution and will persist
through any following asynchronous calls.
Example:
const store = { id: 1 };
asyncLocalStorage.enterWith(store);
asyncLocalStorage.getStore(); // Returns the store object
someAsyncOperation(() => {
asyncLocalStorage.getStore(); // Returns the same object
});
This transition will continue for the entire synchronous execution.
This means that if, for example, the context is entered within an event
handler subsequent event handlers will also run within that context unless
specifically bound to another context with an AsyncResource
.
const store = { id: 1 };
emitter.on('my-event', () => {
asyncLocalStorage.enterWith(store);
});
emitter.on('my-event', () => {
asyncLocalStorage.getStore(); // Returns the same object
});
asyncLocalStorage.getStore(); // Returns undefined
emitter.emit('my-event');
asyncLocalStorage.getStore(); // Returns the same object
asyncLocalStorage.run(store, callback[, ...args])
#
store
<any>callback
<Function>...args
<any>
This methods runs a function synchronously within a context and return its return value. The store is not accessible outside of the callback function or the asynchronous operations created within the callback.
Optionally, arguments can be passed to the function. They will be passed to the callback function.
If the callback function throws an error, it will be thrown by run
too.
The stacktrace will not be impacted by this call and the context will
be exited.
Example:
const store = { id: 2 };
try {
asyncLocalStorage.run(store, () => {
asyncLocalStorage.getStore(); // Returns the store object
throw new Error();
});
} catch (e) {
asyncLocalStorage.getStore(); // Returns undefined
// The error will be caught here
}
asyncLocalStorage.exit(callback[, ...args])
#
callback
<Function>...args
<any>
This methods runs a function synchronously outside of a context and return its return value. The store is not accessible within the callback function or the asynchronous operations created within the callback.
Optionally, arguments can be passed to the function. They will be passed to the callback function.
If the callback function throws an error, it will be thrown by exit
too.
The stacktrace will not be impacted by this call and
the context will be re-entered.
Example:
// Within a call to run
try {
asyncLocalStorage.getStore(); // Returns the store object or value
asyncLocalStorage.exit(() => {
asyncLocalStorage.getStore(); // Returns undefined
throw new Error();
});
} catch (e) {
asyncLocalStorage.getStore(); // Returns the same object or value
// The error will be caught here
}
Usage with async/await
#
If, within an async function, only one await
call is to run within a context,
the following pattern should be used:
async function fn() {
await asyncLocalStorage.run(new Map(), () => {
asyncLocalStorage.getStore().set('key', value);
return foo(); // The return value of foo will be awaited
});
}
In this example, the store is only available in the callback function and the
functions called by foo
. Outside of run
, calling getStore
will return
undefined
.
Troubleshooting#
In most cases your application or library code should have no issues with
AsyncLocalStorage
. But in rare cases you may face situations when the
current store is lost in one of asynchronous operations. In those cases,
consider the following options.
If your code is callback-based, it is enough to promisify it with
util.promisify()
, so it starts working with native promises.
If you need to keep using callback-based API, or your code assumes
a custom thenable implementation, use the AsyncResource
class
to associate the asynchronous operation with the correct execution context.
Buffer#
Source Code: lib/buffer.js
Buffer
objects are used to represent a fixed-length sequence of bytes. Many
Node.js APIs support Buffer
s.
The Buffer
class is a subclass of JavaScript's Uint8Array
class and
extends it with methods that cover additional use cases. Node.js APIs accept
plain Uint8Array
s wherever Buffer
s are supported as well.
The Buffer
class is within the global scope, making it unlikely that one
would need to ever use require('buffer').Buffer
.
// Creates a zero-filled Buffer of length 10.
const buf1 = Buffer.alloc(10);
// Creates a Buffer of length 10,
// filled with bytes which all have the value `1`.
const buf2 = Buffer.alloc(10, 1);
// Creates an uninitialized buffer of length 10.
// This is faster than calling Buffer.alloc() but the returned
// Buffer instance might contain old data that needs to be
// overwritten using fill(), write(), or other functions that fill the Buffer's
// contents.
const buf3 = Buffer.allocUnsafe(10);
// Creates a Buffer containing the bytes [1, 2, 3].
const buf4 = Buffer.from([1, 2, 3]);
// Creates a Buffer containing the bytes [1, 1, 1, 1] – the entries
// are all truncated using `(value & 255)` to fit into the range 0–255.
const buf5 = Buffer.from([257, 257.5, -255, '1']);
// Creates a Buffer containing the UTF-8-encoded bytes for the string 'tést':
// [0x74, 0xc3, 0xa9, 0x73, 0x74] (in hexadecimal notation)
// [116, 195, 169, 115, 116] (in decimal notation)
const buf6 = Buffer.from('tést');
// Creates a Buffer containing the Latin-1 bytes [0x74, 0xe9, 0x73, 0x74].
const buf7 = Buffer.from('tést', 'latin1');
Buffers and character encodings#
When converting between Buffer
s and strings, a character encoding may be
specified. If no character encoding is specified, UTF-8 will be used as the
default.
const buf = Buffer.from('hello world', 'utf8');
console.log(buf.toString('hex'));
// Prints: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
// Prints: aGVsbG8gd29ybGQ=
console.log(Buffer.from('fhqwhgads', 'utf8'));
// Prints: <Buffer 66 68 71 77 68 67 61 64 73>
console.log(Buffer.from('fhqwhgads', 'utf16le'));
// Prints: <Buffer 66 00 68 00 71 00 77 00 68 00 67 00 61 00 64 00 73 00>
The character encodings currently supported by Node.js are the following:
-
'utf8'
: Multi-byte encoded Unicode characters. Many web pages and other document formats use UTF-8. This is the default character encoding. When decoding aBuffer
into a string that does not exclusively contain valid UTF-8 data, the Unicode replacement characterU+FFFD
� will be used to represent those errors. -
'utf16le'
: Multi-byte encoded Unicode characters. Unlike'utf8'
, each character in the string will be encoded using either 2 or 4 bytes. Node.js only supports the little-endian variant of UTF-16. -
'latin1'
: Latin-1 stands for ISO-8859-1. This character encoding only supports the Unicode characters fromU+0000
toU+00FF
. Each character is encoded using a single byte. Characters that do not fit into that range are truncated and will be mapped to characters in that range.
Converting a Buffer
into a string using one of the above is referred to as
decoding, and converting a string into a Buffer
is referred to as encoding.
Node.js also supports the following two binary-to-text encodings. For
binary-to-text encodings, the naming convention is reversed: Converting a
Buffer
into a string is typically referred to as encoding, and converting a
string into a Buffer
as decoding.
-
'base64'
: Base64 encoding. When creating aBuffer
from a string, this encoding will also correctly accept "URL and Filename Safe Alphabet" as specified in RFC 4648, Section 5. Whitespace characters such as spaces, tabs, and new lines contained within the base64-encoded string are ignored. -
'hex'
: Encode each byte as two hexadecimal characters. Data truncation may occur when decoding strings that do exclusively contain valid hexadecimal characters. See below for an example.
The following legacy character encodings are also supported:
-
'ascii'
: For 7-bit ASCII data only. When encoding a string into aBuffer
, this is equivalent to using'latin1'
. When decoding aBuffer
into a string, using this encoding will additionally unset the highest bit of each byte before decoding as'latin1'
. Generally, there should be no reason to use this encoding, as'utf8'
(or, if the data is known to always be ASCII-only,'latin1'
) will be a better choice when encoding or decoding ASCII-only text. It is only provided for legacy compatibility. -
'binary'
: Alias for'latin1'
. See binary strings for more background on this topic. The name of this encoding can be very misleading, as all of the encodings listed here convert between strings and binary data. For converting between strings andBuffer
s, typically'utf-8'
is the right choice. -
'ucs2'
: Alias of'utf16le'
. UCS-2 used to refer to a variant of UTF-16 that did not support characters that had code points larger than U+FFFF. In Node.js, these code points are always supported.
Buffer.from('1ag', 'hex');
// Prints <Buffer 1a>, data truncated when first non-hexadecimal value
// ('g') encountered.
Buffer.from('1a7g', 'hex');
// Prints <Buffer 1a>, data truncated when data ends in single digit ('7').
Buffer.from('1634', 'hex');
// Prints <Buffer 16 34>, all data represented.
Modern Web browsers follow the WHATWG Encoding Standard which aliases
both 'latin1'
and 'ISO-8859-1'
to 'win-1252'
. This means that while doing
something like http.get()
, if the returned charset is one of those listed in
the WHATWG specification it is possible that the server actually returned
'win-1252'
-encoded data, and using 'latin1'
encoding may incorrectly decode
the characters.
Buffers and TypedArrays#
Buffer
instances are also JavaScript Uint8Array
and TypedArray
instances. All TypedArray
methods are available on Buffer
s. There are,
however, subtle incompatibilities between the Buffer
API and the
TypedArray
API.
In particular:
- While
TypedArray#slice()
creates a copy of part of theTypedArray
,Buffer#slice()
creates a view over the existingBuffer
without copying. This behavior can be surprising, and only exists for legacy compatibility.TypedArray#subarray()
can be used to achieve the behavior ofBuffer#slice()
on bothBuffer
s and otherTypedArray
s. buf.toString()
is incompatible with itsTypedArray
equivalent.- A number of methods, e.g.
buf.indexOf()
, support additional arguments.
There are two ways to create new TypedArray
instances from a Buffer
:
- Passing a
Buffer
to aTypedArray
constructor will copy theBuffer
s contents, interpreted as an array of integers, and not as a byte sequence of the target type.
const buf = Buffer.from([1, 2, 3, 4]);
const uint32array = new Uint32Array(buf);
console.log(uint32array);
// Prints: Uint32Array(4) [ 1, 2, 3, 4 ]
- Passing the
Buffer
s underlyingArrayBuffer
will create aTypedArray
that shares its memory with theBuffer
.
const buf = Buffer.from('hello', 'utf16le');
const uint16arr = new Uint16Array(
buf.buffer,
buf.byteOffset,
buf.length / Uint16Array.BYTES_PER_ELEMENT);
console.log(uint16array);
// Prints: Uint16Array(5) [ 104, 101, 108, 108, 111 ]
It is possible to create a new Buffer
that shares the same allocated
memory as a TypedArray
instance by using the TypedArray
object’s
.buffer
property in the same way. Buffer.from()
behaves like new Uint8Array()
in this context.
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// Copies the contents of `arr`.
const buf1 = Buffer.from(arr);
// Shares memory with `arr`.
const buf2 = Buffer.from(arr.buffer);
console.log(buf1);
// Prints: <Buffer 88 a0>
console.log(buf2);
// Prints: <Buffer 88 13 a0 0f>
arr[1] = 6000;
console.log(buf1);
// Prints: <Buffer 88 a0>
console.log(buf2);
// Prints: <Buffer 88 13 70 17>
When creating a Buffer
using a TypedArray
's .buffer
, it is
possible to use only a portion of the underlying ArrayBuffer
by passing in
byteOffset
and length
parameters.
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
console.log(buf.length);
// Prints: 16
The Buffer.from()
and TypedArray.from()
have different signatures and
implementations. Specifically, the TypedArray
variants accept a second
argument that is a mapping function that is invoked on every element of the
typed array:
TypedArray.from(source[, mapFn[, thisArg]])
The Buffer.from()
method, however, does not support the use of a mapping
function:
Buffer.from(array)
Buffer.from(buffer)
Buffer.from(arrayBuffer[, byteOffset[, length]])
Buffer.from(string[, encoding])
Buffers and iteration#
Buffer
instances can be iterated over using for..of
syntax:
const buf = Buffer.from([1, 2, 3]);
for (const b of buf) {
console.log(b);
}
// Prints:
// 1
// 2
// 3
Additionally, the buf.values()
, buf.keys()
, and
buf.entries()
methods can be used to create iterators.
Class: Buffer
#
The Buffer
class is a global type for dealing with binary data directly.
It can be constructed in a variety of ways.
Static method: Buffer.alloc(size[, fill[, encoding]])
#
size
<integer> The desired length of the newBuffer
.fill
<string> | <Buffer> | <Uint8Array> | <integer> A value to pre-fill the newBuffer
with. Default:0
.encoding
<string> Iffill
is a string, this is its encoding. Default:'utf8'
.
Allocates a new Buffer
of size
bytes. If fill
is undefined
, the
Buffer
will be zero-filled.
const buf = Buffer.alloc(5);
console.log(buf);
// Prints: <Buffer 00 00 00 00 00>
If size
is larger than
buffer.constants.MAX_LENGTH
or smaller than 0, ERR_INVALID_OPT_VALUE
is thrown.
If fill
is specified, the allocated Buffer
will be initialized by calling
buf.fill(fill)
.
const buf = Buffer.alloc(5, 'a');
console.log(buf);
// Prints: <Buffer 61 61 61 61 61>
If both fill
and encoding
are specified, the allocated Buffer
will be
initialized by calling buf.fill(fill, encoding)
.
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
console.log(buf);
// Prints: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
Calling Buffer.alloc()
can be measurably slower than the alternative
Buffer.allocUnsafe()
but ensures that the newly created Buffer
instance
contents will never contain sensitive data from previous allocations, including
data that might not have been allocated for Buffer
s.
A TypeError
will be thrown if size
is not a number.
Static method: Buffer.allocUnsafe(size)
#
size
<integer> The desired length of the newBuffer
.
Allocates a new Buffer
of size
bytes. If size
is larger than
buffer.constants.MAX_LENGTH
or smaller than 0, ERR_INVALID_OPT_VALUE
is thrown.
The underlying memory for Buffer
instances created in this way is not
initialized. The contents of the newly created Buffer
are unknown and
may contain sensitive data. Use Buffer.alloc()
instead to initialize
Buffer
instances with zeroes.
const buf = Buffer.allocUnsafe(10);
console.log(buf);
// Prints (contents may vary): <Buffer a0 8b 28 3f 01 00 00 00 50 32>
buf.fill(0);
console.log(buf);
// Prints: <Buffer 00 00 00 00 00 00 00 00 00 00>
A TypeError
will be thrown if size
is not a number.
The Buffer
module pre-allocates an internal Buffer
instance of
size Buffer.poolSize
that is used as a pool for the fast allocation of new
Buffer
instances created using Buffer.allocUnsafe()
,
Buffer.from(array)
, Buffer.concat()
, and the deprecated
new Buffer(size)
constructor only when size
is less than or equal
to Buffer.poolSize >> 1
(floor of Buffer.poolSize
divided by two).
Use of this pre-allocated internal memory pool is a key difference between
calling Buffer.alloc(size, fill)
vs. Buffer.allocUnsafe(size).fill(fill)
.
Specifically, Buffer.alloc(size, fill)
will never use the internal Buffer
pool, while Buffer.allocUnsafe(size).fill(fill)
will use the internal
Buffer
pool if size
is less than or equal to half Buffer.poolSize
. The
difference is subtle but can be important when an application requires the
additional performance that Buffer.allocUnsafe()
provides.
Static method: Buffer.allocUnsafeSlow(size)
#
size
<integer> The desired length of the newBuffer
.
Allocates a new Buffer
of size
bytes. If size
is larger than
buffer.constants.MAX_LENGTH
or smaller than 0, ERR_INVALID_OPT_VALUE
is thrown. A zero-length Buffer
is created if size
is 0.
The underlying memory for Buffer
instances created in this way is not
initialized. The contents of the newly created Buffer
are unknown and
may contain sensitive data. Use buf.fill(0)
to initialize
such Buffer
instances with zeroes.
When using Buffer.allocUnsafe()
to allocate new Buffer
instances,
allocations under 4KB are sliced from a single pre-allocated Buffer
. This
allows applications to avoid the garbage collection overhead of creating many
individually allocated Buffer
instances. This approach improves both
performance and memory usage by eliminating the need to track and clean up as
many individual ArrayBuffer
objects.
However, in the case where a developer may need to retain a small chunk of
memory from a pool for an indeterminate amount of time, it may be appropriate
to create an un-pooled Buffer
instance using Buffer.allocUnsafeSlow()
and
then copying out the relevant bits.
// Need to keep around a few small chunks of memory.
const store = [];
socket.on('readable', () => {
let data;
while (null !== (data = readable.read())) {
// Allocate for retained data.
const sb = Buffer.allocUnsafeSlow(10);
// Copy the data into the new allocation.
data.copy(sb, 0, 0, 10);
store.push(sb);
}
});
A TypeError
will be thrown if size
is not a number.
Static method: Buffer.byteLength(string[, encoding])
#
string
<string> | <Buffer> | <TypedArray> | <DataView> | <ArrayBuffer> | <SharedArrayBuffer> A value to calculate the length of.encoding
<string> Ifstring
is a string, this is its encoding. Default:'utf8'
.- Returns: <integer> The number of bytes contained within
string
.
Returns the byte length of a string when encoded using encoding
.
This is not the same as String.prototype.length
, which does not account
for the encoding that is used to convert the string into bytes.
For 'base64'
and 'hex'
, this function assumes valid input. For strings that
contain non-base64/hex-encoded data (e.g. whitespace), the return value might be
greater than the length of a Buffer
created from the string.
const str = '\u00bd + \u00bc = \u00be';
console.log(`${str}: ${str.length} characters, ` +
`${Buffer.byteLength(str, 'utf8')} bytes`);
// Prints: ½ + ¼ = ¾: 9 characters, 12 bytes
When string
is a Buffer
/DataView
/TypedArray
/ArrayBuffer
/
SharedArrayBuffer
, the byte length as reported by .byteLength
is returned.
Static method: Buffer.compare(buf1, buf2)
#
buf1
<Buffer> | <Uint8Array>buf2
<Buffer> | <Uint8Array>- Returns: <integer> Either
-1
,0
, or1
, depending on the result of the comparison. Seebuf.compare()
for details.
Compares buf1
to buf2
, typically for the purpose of sorting arrays of
Buffer
instances. This is equivalent to calling
buf1.compare(buf2)
.
const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');
const arr = [buf1, buf2];
console.log(arr.sort(Buffer.compare));
// Prints: [ <Buffer 30 31 32 33>, <Buffer 31 32 33 34> ]
// (This result is equal to: [buf2, buf1].)
Static method: Buffer.concat(list[, totalLength])
#
list
<Buffer[]> | <Uint8Array[]> List ofBuffer
orUint8Array
instances to concatenate.totalLength
<integer> Total length of theBuffer
instances inlist
when concatenated.- Returns: <Buffer>
Returns a new Buffer
which is the result of concatenating all the Buffer
instances in the list
together.
If the list has no items, or if the totalLength
is 0, then a new zero-length
Buffer
is returned.
If totalLength
is not provided, it is calculated from the Buffer
instances
in list
by adding their lengths.
If totalLength
is provided, it is coerced to an unsigned integer. If the
combined length of the Buffer
s in list
exceeds totalLength
, the result is
truncated to totalLength
.
// Create a single `Buffer` from a list of three `Buffer` instances.
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;
console.log(totalLength);
// Prints: 42
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
console.log(bufA);
// Prints: <Buffer 00 00 00 00 ...>
console.log(bufA.length);
// Prints: 42
Buffer.concat()
may also use the internal Buffer
pool like
Buffer.allocUnsafe()
does.
Static method: Buffer.from(array)
#
array
<integer[]>
Allocates a new Buffer
using an array
of bytes in the range 0
– 255
.
Array entries outside that range will be truncated to fit into it.
// Creates a new Buffer containing the UTF-8 bytes of the string 'buffer'.
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
A TypeError
will be thrown if array
is not an Array
or another type
appropriate for Buffer.from()
variants.
Buffer.from(array)
and Buffer.from(string)
may also use the internal
Buffer
pool like Buffer.allocUnsafe()
does.
Static method: Buffer.from(arrayBuffer[, byteOffset[, length]])
#
arrayBuffer
<ArrayBuffer> | <SharedArrayBuffer> AnArrayBuffer
,SharedArrayBuffer
, for example the.buffer
property of aTypedArray
.byteOffset
<integer> Index of first byte to expose. Default:0
.length
<integer> Number of bytes to expose. Default:arrayBuffer.byteLength - byteOffset
.
This creates a view of the ArrayBuffer
without copying the underlying
memory. For example, when passed a reference to the .buffer
property of a
TypedArray
instance, the newly created Buffer
will share the same
allocated memory as the TypedArray
.
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
// Shares memory with `arr`.
const buf = Buffer.from(arr.buffer);
console.log(buf);
// Prints: <Buffer 88 13 a0 0f>
// Changing the original Uint16Array changes the Buffer also.
arr[1] = 6000;
console.log(buf);
// Prints: <Buffer 88 13 70 17>
The optional byteOffset
and length
arguments specify a memory range within
the arrayBuffer
that will be shared by the Buffer
.
const ab = new ArrayBuffer(10);
const buf = Buffer.from(ab, 0, 2);
console.log(buf.length);
// Prints: 2
A TypeError
will be thrown if arrayBuffer
is not an ArrayBuffer
or a
SharedArrayBuffer
or another type appropriate for Buffer.from()
variants.
Static method: Buffer.from(buffer)
#
buffer
<Buffer> | <Uint8Array> An existingBuffer
orUint8Array
from which to copy data.
Copies the passed buffer
data onto a new Buffer
instance.
const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);
buf1[0] = 0x61;
console.log(buf1.toString());
// Prints: auffer
console.log(buf2.toString());
// Prints: buffer
A TypeError
will be thrown if buffer
is not a Buffer
or another type
appropriate for Buffer.from()
variants.
Static method: Buffer.from(object[, offsetOrEncoding[, length]])
#
object
<Object> An object supportingSymbol.toPrimitive
orvalueOf()
.offsetOrEncoding
<integer> | <string> A byte-offset or encoding.length
<integer> A length.
For objects whose valueOf()
function returns a value not strictly equal to
object
, returns Buffer.from(object.valueOf(), offsetOrEncoding, length)
.
const buf = Buffer.from(new String('this is a test'));
// Prints: <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
For objects that support Symbol.toPrimitive
, returns
Buffer.from(object[Symbol.toPrimitive]('string'), offsetOrEncoding)
.
class Foo {
[Symbol.toPrimitive]() {
return 'this is a test';
}
}
const buf = Buffer.from(new Foo(), 'utf8');
// Prints: <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
A TypeError
will be thrown if object
does not have the mentioned methods or
is not of another type appropriate for Buffer.from()
variants.
Static method: Buffer.from(string[, encoding])
#
Creates a new Buffer
containing string
. The encoding
parameter identifies
the character encoding to be used when converting string
into bytes.
const buf1 = Buffer.from('this is a tést');
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
console.log(buf1.toString());
// Prints: this is a tést
console.log(buf2.toString());
// Prints: this is a tést
console.log(buf1.toString('latin1'));
// Prints: this is a tést
A TypeError
will be thrown if string
is not a string or another type
appropriate for Buffer.from()
variants.
Static method: Buffer.isBuffer(obj)
#
Returns true
if obj
is a Buffer
, false
otherwise.
Static method: Buffer.isEncoding(encoding)
#
Returns true
if encoding
is the name of a supported character encoding,
or false
otherwise.
console.log(Buffer.isEncoding('utf-8'));
// Prints: true
console.log(Buffer.isEncoding('hex'));
// Prints: true
console.log(Buffer.isEncoding('utf/8'));
// Prints: false
console.log(Buffer.isEncoding(''));
// Prints: false
Class property: Buffer.poolSize
#
- <integer> Default:
8192
This is the size (in bytes) of pre-allocated internal Buffer
instances used
for pooling. This value may be modified.
buf[index]
#
index
<integer>
The index operator [index]
can be used to get and set the octet at position
index
in buf
. The values refer to individual bytes, so the legal value
range is between 0x00
and 0xFF
(hex) or 0
and 255
(decimal).
This operator is inherited from Uint8Array
, so its behavior on out-of-bounds
access is the same as Uint8Array
. In other words, buf[index]
returns
undefined
when index
is negative or greater or equal to buf.length
, and
buf[index] = value
does not modify the buffer if index
is negative or
>= buf.length
.
// Copy an ASCII string into a `Buffer` one byte at a time.
// (This only works for ASCII-only strings. In general, one should use
// `Buffer.from()` to perform this conversion.)
const str = 'Node.js';
const buf = Buffer.allocUnsafe(str.length);
for (let i = 0; i < str.length; i++) {
buf[i] = str.charCodeAt(i);
}
console.log(buf.toString('utf8'));
// Prints: Node.js
buf.buffer
#
- <ArrayBuffer> The underlying
ArrayBuffer
object based on which thisBuffer
object is created.
This ArrayBuffer
is not guaranteed to correspond exactly to the original
Buffer
. See the notes on buf.byteOffset
for details.
const arrayBuffer = new ArrayBuffer(16);
const buffer = Buffer.from(arrayBuffer);
console.log(buffer.buffer === arrayBuffer);
// Prints: true
buf.byteOffset
#
- <integer> The
byteOffset
of theBuffer
s underlyingArrayBuffer
object.
When setting byteOffset
in Buffer.from(ArrayBuffer, byteOffset, length)
,
or sometimes when allocating a Buffer
smaller than Buffer.poolSize
, the
buffer does not start from a zero offset on the underlying ArrayBuffer
.
This can cause problems when accessing the underlying ArrayBuffer
directly
using buf.buffer
, as other parts of the ArrayBuffer
may be unrelated
to the Buffer
object itself.
A common issue when creating a TypedArray
object that shares its memory with
a Buffer
is that in this case one needs to specify the byteOffset
correctly:
// Create a buffer smaller than `Buffer.poolSize`.
const nodeBuffer = new Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
// When casting the Node.js Buffer to an Int8Array, use the byteOffset
// to refer only to the part of `nodeBuffer.buffer` that contains the memory
// for `nodeBuffer`.
new Int8Array(nodeBuffer.buffer, nodeBuffer.byteOffset, nodeBuffer.length);
buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])
#
target
<Buffer> | <Uint8Array> ABuffer
orUint8Array
with which to comparebuf
.targetStart
<integer> The offset withintarget
at which to begin comparison. Default:0
.targetEnd
<integer> The offset withintarget
at which to end comparison (not inclusive). Default:target.length
.sourceStart
<integer> The offset withinbuf
at which to begin comparison. Default:0
.sourceEnd
<integer> The offset withinbuf
at which to end comparison (not inclusive). Default:buf.length
.- Returns: <integer>
Compares buf
with target
and returns a number indicating whether buf
comes before, after, or is the same as target
in sort order.
Comparison is based on the actual sequence of bytes in each Buffer
.
0
is returned iftarget
is the same asbuf
1
is returned iftarget
should come beforebuf
when sorted.-1
is returned iftarget
should come afterbuf
when sorted.
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');
console.log(buf1.compare(buf1));
// Prints: 0
console.log(buf1.compare(buf2));
// Prints: -1
console.log(buf1.compare(buf3));
// Prints: -1
console.log(buf2.compare(buf1));
// Prints: 1
console.log(buf2.compare(buf3));
// Prints: 1
console.log([buf1, buf2, buf3].sort(Buffer.compare));
// Prints: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
// (This result is equal to: [buf1, buf3, buf2].)
The optional targetStart
, targetEnd
, sourceStart
, and sourceEnd
arguments can be used to limit the comparison to specific ranges within target
and buf
respectively.
const buf1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
const buf2 = Buffer.from([5, 6, 7, 8, 9, 1, 2, 3, 4]);
console.log(buf1.compare(buf2, 5, 9, 0, 4));
// Prints: 0
console.log(buf1.compare(buf2, 0, 6, 4));
// Prints: -1
console.log(buf1.compare(buf2, 5, 6, 5));
// Prints: 1
ERR_OUT_OF_RANGE
is thrown if targetStart < 0
, sourceStart < 0
,
targetEnd > target.byteLength
, or sourceEnd > source.byteLength
.
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
#
target
<Buffer> | <Uint8Array> ABuffer
orUint8Array
to copy into.targetStart
<integer> The offset withintarget
at which to begin writing. Default:0
.sourceStart
<integer> The offset withinbuf
from which to begin copying. Default:0
.sourceEnd
<integer> The offset withinbuf
at which to stop copying (not inclusive). Default:buf.length
.- Returns: <integer> The number of bytes copied.
Copies data from a region of buf
to a region in target
, even if the target
memory region overlaps with buf
.
TypedArray#set()
performs the same operation, and is available for all
TypedArrays, including Node.js Buffer
s, although it takes different
function arguments.
// Create two `Buffer` instances.
const buf1 = Buffer.allocUnsafe(26);
const buf2 = Buffer.allocUnsafe(26).fill('!');
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
// Copy `buf1` bytes 16 through 19 into `buf2` starting at byte 8 of `buf2`.
buf1.copy(buf2, 8, 16, 20);
// This is equivalent to:
// buf2.set(buf1.subarray(16, 20), 8);
console.log(buf2.toString('ascii', 0, 25));
// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
// Create a `Buffer` and copy data from one region to an overlapping region
// within the same `Buffer`.
const buf = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf[i] = i + 97;
}
buf.copy(buf, 0, 4, 10);
console.log(buf.toString());
// Prints: efghijghijklmnopqrstuvwxyz
buf.entries()
#
- Returns: <Iterator>
Creates and returns an iterator of [index, byte]
pairs from the contents
of buf
.
// Log the entire contents of a `Buffer`.
const buf = Buffer.from('buffer');
for (const pair of buf.entries()) {
console.log(pair);
}
// Prints:
// [0, 98]
// [1, 117]
// [2, 102]
// [3, 102]
// [4, 101]
// [5, 114]
buf.equals(otherBuffer)
#
otherBuffer
<Buffer> | <Uint8Array> ABuffer
orUint8Array
with which to comparebuf
.- Returns: <boolean>
Returns true
if both buf
and otherBuffer
have exactly the same bytes,
false
otherwise. Equivalent to
buf.compare(otherBuffer) === 0
.
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
console.log(buf1.equals(buf2));
// Prints: true
console.log(buf1.equals(buf3));
// Prints: false
buf.fill(value[, offset[, end]][, encoding])
#
value
<string> | <Buffer> | <Uint8Array> | <integer> The value with which to fillbuf
.offset
<integer> Number of bytes to skip before starting to fillbuf
. Default:0
.end
<integer> Where to stop fillingbuf
(not inclusive). Default:buf.length
.encoding
<string> The encoding forvalue
ifvalue
is a string. Default:'utf8'
.- Returns: <Buffer> A reference to
buf
.
Fills buf
with the specified value
. If the offset
and end
are not given,
the entire buf
will be filled:
// Fill a `Buffer` with the ASCII character 'h'.
const b = Buffer.allocUnsafe(50).fill('h');
console.log(b.toString());
// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
value
is coerced to a uint32
value if it is not a string, Buffer
, or
integer. If the resulting integer is greater than 255
(decimal), buf
will be
filled with value & 255
.
If the final write of a fill()
operation falls on a multi-byte character,
then only the bytes of that character that fit into buf
are written:
// Fill a `Buffer` with character that takes up two bytes in UTF-8.
console.log(Buffer.allocUnsafe(5).fill('\u0222'));
// Prints: <Buffer c8 a2 c8 a2 c8>
If value
contains invalid characters, it is truncated; if no valid
fill data remains, an exception is thrown:
const buf = Buffer.allocUnsafe(5);
console.log(buf.fill('a'));
// Prints: <Buffer 61 61 61 61 61>
console.log(buf.fill('aazz', 'hex'));
// Prints: <Buffer aa aa aa aa aa>
console.log(buf.fill('zz', 'hex'));
// Throws an exception.
buf.includes(value[, byteOffset][, encoding])
#
value
<string> | <Buffer> | <Uint8Array> | <integer> What to search for.byteOffset
<integer> Where to begin searching inbuf
. If negative, then offset is calculated from the end ofbuf
. Default:0
.encoding
<string> Ifvalue
is a string, this is its encoding. Default:'utf8'
.- Returns: <boolean>
true
ifvalue
was found inbuf
,false
otherwise.
Equivalent to buf.indexOf() !== -1
.
const buf = Buffer.from('this is a buffer');
console.log(buf.includes('this'));
// Prints: true
console.log(buf.includes('is'));
// Prints: true
console.log(buf.includes(Buffer.from('a buffer')));
// Prints: true
console.log(buf.includes(97));
// Prints: true (97 is the decimal ASCII value for 'a')
console.log(buf.includes(Buffer.from('a buffer example')));
// Prints: false
console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
// Prints: true
console.log(buf.includes('this', 4));
// Prints: false
buf.indexOf(value[, byteOffset][, encoding])
#
value
<string> | <Buffer> | <Uint8Array> | <integer> What to search for.byteOffset
<integer> Where to begin searching inbuf
. If negative, then offset is calculated from the end ofbuf
. Default:0
.encoding
<string> Ifvalue
is a string, this is the encoding used to determine the binary representation of the string that will be searched for inbuf
. Default:'utf8'
.- Returns: <integer> The index of the first occurrence of
value
inbuf
, or-1
ifbuf
does not containvalue
.
If value
is:
- a string,
value
is interpreted according to the character encoding inencoding
. - a
Buffer
orUint8Array
,value
will be used in its entirety. To compare a partialBuffer
, usebuf.slice()
. - a number,
value
will be interpreted as an unsigned 8-bit integer value between0
and255
.
const buf = Buffer.from('this is a buffer');
console.log(buf.indexOf('this'));
// Prints: 0
console.log(buf.indexOf('is'));
// Prints: 2
console.log(buf.indexOf(Buffer.from('a buffer')));
// Prints: 8
console.log(buf.indexOf(97));
// Prints: 8 (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(Buffer.from('a buffer example')));
// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
// Prints: 8
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
console.log(utf16Buffer.indexOf('\u03a3', 0, 'utf16le'));
// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', -4, 'utf16le'));
// Prints: 6
If value
is not a string, number, or Buffer
, this method will throw a
TypeError
. If value
is a number, it will be coerced to a valid byte value,
an integer between 0 and 255.
If byteOffset
is not a number, it will be coerced to a number. If the result
of coercion is NaN
or 0
, then the entire buffer will be searched. This
behavior matches String#indexOf()
.
const b = Buffer.from('abcdef');
// Passing a value that's a number, but not a valid byte.
// Prints: 2, equivalent to searching for 99 or 'c'.
console.log(b.indexOf(99.9));
console.log(b.indexOf(256 + 99));
// Passing a byteOffset that coerces to NaN or 0.
// Prints: 1, searching the whole buffer.
console.log(b.indexOf('b', undefined));
console.log(b.indexOf('b', {}));
console.log(b.indexOf('b', null));
console.log(b.indexOf('b', []));
If value
is an empty string or empty Buffer
and byteOffset
is less
than buf.length
, byteOffset
will be returned. If value
is empty and
byteOffset
is at least buf.length
, buf.length
will be returned.
buf.keys()
#
- Returns: <Iterator>
Creates and returns an iterator of buf
keys (indices).
const buf = Buffer.from('buffer');
for (const key of buf.keys()) {
console.log(key);
}
// Prints:
// 0
// 1
// 2
// 3
// 4
// 5
buf.lastIndexOf(value[, byteOffset][, encoding])
#
value
<string> | <Buffer> | <Uint8Array> | <integer> What to search for.byteOffset
<integer> Where to begin searching inbuf
. If negative, then offset is calculated from the end ofbuf
. Default:buf.length - 1
.encoding
<string> Ifvalue
is a string, this is the encoding used to determine the binary representation of the string that will be searched for inbuf
. Default:'utf8'
.- Returns: <integer> The index of the last occurrence of
value
inbuf
, or-1
ifbuf
does not containvalue
.
Identical to buf.indexOf()
, except the last occurrence of value
is found
rather than the first occurrence.
const buf = Buffer.from('this buffer is a buffer');
console.log(buf.lastIndexOf('this'));
// Prints: 0
console.log(buf.lastIndexOf('buffer'));
// Prints: 17
console.log(buf.lastIndexOf(Buffer.from('buffer')));
// Prints: 17
console.log(buf.lastIndexOf(97));
// Prints: 15 (97 is the decimal ASCII value for 'a')
console.log(buf.lastIndexOf(Buffer.from('yolo')));
// Prints: -1
console.log(buf.lastIndexOf('buffer', 5));
// Prints: 5
console.log(buf.lastIndexOf('buffer', 4));
// Prints: -1
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'utf16le'));
// Prints: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'utf16le'));
// Prints: 4
If value
is not a string, number, or Buffer
, this method will throw a
TypeError
. If value
is a number, it will be coerced to a valid byte value,
an integer between 0 and 255.
If byteOffset
is not a number, it will be coerced to a number. Any arguments
that coerce to NaN
, like {}
or undefined
, will search the whole buffer.
This behavior matches String#lastIndexOf()
.
const b = Buffer.from('abcdef');
// Passing a value that's a number, but not a valid byte.
// Prints: 2, equivalent to searching for 99 or 'c'.
console.log(b.lastIndexOf(99.9));
console.log(b.lastIndexOf(256 + 99));
// Passing a byteOffset that coerces to NaN.
// Prints: 1, searching the whole buffer.
console.log(b.lastIndexOf('b', undefined));
console.log(b.lastIndexOf('b', {}));
// Passing a byteOffset that coerces to 0.
// Prints: -1, equivalent to passing 0.
console.log(b.lastIndexOf('b', null));
console.log(b.lastIndexOf('b', []));
If value
is an empty string or empty Buffer
, byteOffset
will be returned.
buf.length
#
Returns the number of bytes in buf
.
// Create a `Buffer` and write a shorter string to it using UTF-8.
const buf = Buffer.alloc(1234);
console.log(buf.length);
// Prints: 1234
buf.write('some string', 0, 'utf8');
console.log(buf.length);
// Prints: 1234
buf.parent
#
buf.buffer
instead.The buf.parent
property is a deprecated alias for buf.buffer
.
buf.readBigInt64BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <bigint>
Reads a signed, big-endian 64-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed
values.
buf.readBigInt64LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <bigint>
Reads a signed, little-endian 64-bit integer from buf
at the specified
offset
.
Integers read from a Buffer
are interpreted as two's complement signed
values.
buf.readBigUInt64BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <bigint>
Reads an unsigned, big-endian 64-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
console.log(buf.readBigUInt64BE(0));
// Prints: 4294967295n
buf.readBigUInt64LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <bigint>
Reads an unsigned, little-endian 64-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
console.log(buf.readBigUInt64LE(0));
// Prints: 18446744069414584320n
buf.readDoubleBE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 8
. Default:0
.- Returns: <number>
Reads a 64-bit, big-endian double from buf
at the specified offset
.
const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(buf.readDoubleBE(0));
// Prints: 8.20788039913184e-304
buf.readDoubleLE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 8
. Default:0
.- Returns: <number>
Reads a 64-bit, little-endian double from buf
at the specified offset
.
const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(buf.readDoubleLE(0));
// Prints: 5.447603722011605e-270
console.log(buf.readDoubleLE(1));
// Throws ERR_OUT_OF_RANGE.
buf.readFloatBE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <number>
Reads a 32-bit, big-endian float from buf
at the specified offset
.
const buf = Buffer.from([1, 2, 3, 4]);
console.log(buf.readFloatBE(0));
// Prints: 2.387939260590663e-38
buf.readFloatLE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <number>
Reads a 32-bit, little-endian float from buf
at the specified offset
.
const buf = Buffer.from([1, 2, 3, 4]);
console.log(buf.readFloatLE(0));
// Prints: 1.539989614439558e-36
console.log(buf.readFloatLE(1));
// Throws ERR_OUT_OF_RANGE.
buf.readInt8([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 1
. Default:0
.- Returns: <integer>
Reads a signed 8-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
const buf = Buffer.from([-1, 5]);
console.log(buf.readInt8(0));
// Prints: -1
console.log(buf.readInt8(1));
// Prints: 5
console.log(buf.readInt8(2));
// Throws ERR_OUT_OF_RANGE.
buf.readInt16BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
Reads a signed, big-endian 16-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
const buf = Buffer.from([0, 5]);
console.log(buf.readInt16BE(0));
// Prints: 5
buf.readInt16LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
Reads a signed, little-endian 16-bit integer from buf
at the specified
offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
const buf = Buffer.from([0, 5]);
console.log(buf.readInt16LE(0));
// Prints: 1280
console.log(buf.readInt16LE(1));
// Throws ERR_OUT_OF_RANGE.
buf.readInt32BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
Reads a signed, big-endian 32-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
const buf = Buffer.from([0, 0, 0, 5]);
console.log(buf.readInt32BE(0));
// Prints: 5
buf.readInt32LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
Reads a signed, little-endian 32-bit integer from buf
at the specified
offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
const buf = Buffer.from([0, 0, 0, 5]);
console.log(buf.readInt32LE(0));
// Prints: 83886080
console.log(buf.readInt32LE(1));
// Throws ERR_OUT_OF_RANGE.
buf.readIntBE(offset, byteLength)
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to read. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as a big-endian, two's complement signed value
supporting up to 48 bits of accuracy.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readIntBE(0, 6).toString(16));
// Prints: 1234567890ab
console.log(buf.readIntBE(1, 6).toString(16));
// Throws ERR_OUT_OF_RANGE.
console.log(buf.readIntBE(1, 0).toString(16));
// Throws ERR_OUT_OF_RANGE.
buf.readIntLE(offset, byteLength)
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to read. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as a little-endian, two's complement signed value
supporting up to 48 bits of accuracy.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readIntLE(0, 6).toString(16));
// Prints: -546f87a9cbee
buf.readUInt8([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 1
. Default:0
.- Returns: <integer>
Reads an unsigned 8-bit integer from buf
at the specified offset
.
const buf = Buffer.from([1, -2]);
console.log(buf.readUInt8(0));
// Prints: 1
console.log(buf.readUInt8(1));
// Prints: 254
console.log(buf.readUInt8(2));
// Throws ERR_OUT_OF_RANGE.
buf.readUInt16BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
Reads an unsigned, big-endian 16-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x12, 0x34, 0x56]);
console.log(buf.readUInt16BE(0).toString(16));
// Prints: 1234
console.log(buf.readUInt16BE(1).toString(16));
// Prints: 3456
buf.readUInt16LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
Reads an unsigned, little-endian 16-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x12, 0x34, 0x56]);
console.log(buf.readUInt16LE(0).toString(16));
// Prints: 3412
console.log(buf.readUInt16LE(1).toString(16));
// Prints: 5634
console.log(buf.readUInt16LE(2).toString(16));
// Throws ERR_OUT_OF_RANGE.
buf.readUInt32BE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
Reads an unsigned, big-endian 32-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
console.log(buf.readUInt32BE(0).toString(16));
// Prints: 12345678
buf.readUInt32LE([offset])
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
Reads an unsigned, little-endian 32-bit integer from buf
at the specified
offset
.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
console.log(buf.readUInt32LE(0).toString(16));
// Prints: 78563412
console.log(buf.readUInt32LE(1).toString(16));
// Throws ERR_OUT_OF_RANGE.
buf.readUIntBE(offset, byteLength)
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to read. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as an unsigned big-endian integer supporting
up to 48 bits of accuracy.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readUIntBE(0, 6).toString(16));
// Prints: 1234567890ab
console.log(buf.readUIntBE(1, 6).toString(16));
// Throws ERR_OUT_OF_RANGE.
buf.readUIntLE(offset, byteLength)
#
offset
<integer> Number of bytes to skip before starting to read. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to read. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as an unsigned, little-endian integer supporting
up to 48 bits of accuracy.
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readUIntLE(0, 6).toString(16));
// Prints: ab9078563412
buf.subarray([start[, end]])
#
start
<integer> Where the newBuffer
will start. Default:0
.end
<integer> Where the newBuffer
will end (not inclusive). Default:buf.length
.- Returns: <Buffer>
Returns a new Buffer
that references the same memory as the original, but
offset and cropped by the start
and end
indices.
Specifying end
greater than buf.length
will return the same result as
that of end
equal to buf.length
.
This method is inherited from TypedArray#subarray()
.
Modifying the new Buffer
slice will modify the memory in the original Buffer
because the allocated memory of the two objects overlap.
// Create a `Buffer` with the ASCII alphabet, take a slice, and modify one byte
// from the original `Buffer`.
const buf1 = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
const buf2 = buf1.subarray(0, 3);
console.log(buf2.toString('ascii', 0, buf2.length));
// Prints: abc
buf1[0] = 33;
console.log(buf2.toString('ascii', 0, buf2.length));
// Prints: !bc
Specifying negative indexes causes the slice to be generated relative to the
end of buf
rather than the beginning.
const buf = Buffer.from('buffer');
console.log(buf.subarray(-6, -1).toString());
// Prints: buffe
// (Equivalent to buf.subarray(0, 5).)
console.log(buf.subarray(-6, -2).toString());
// Prints: buff
// (Equivalent to buf.subarray(0, 4).)
console.log(buf.subarray(-5, -2).toString());
// Prints: uff
// (Equivalent to buf.subarray(1, 4).)
buf.slice([start[, end]])
#
start
<integer> Where the newBuffer
will start. Default:0
.end
<integer> Where the newBuffer
will end (not inclusive). Default:buf.length
.- Returns: <Buffer>
Returns a new Buffer
that references the same memory as the original, but
offset and cropped by the start
and end
indices.
This is the same behavior as buf.subarray()
.
This method is not compatible with the Uint8Array.prototype.slice()
,
which is a superclass of Buffer
. To copy the slice, use
Uint8Array.prototype.slice()
.
const buf = Buffer.from('buffer');
const copiedBuf = Uint8Array.prototype.slice.call(buf);
copiedBuf[0]++;
console.log(copiedBuf.toString());
// Prints: cuffer
console.log(buf.toString());
// Prints: buffer
buf.swap16()
#
- Returns: <Buffer> A reference to
buf
.
Interprets buf
as an array of unsigned 16-bit integers and swaps the
byte order in-place. Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 2.
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap16();
console.log(buf1);
// Prints: <Buffer 02 01 04 03 06 05 08 07>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap16();
// Throws ERR_INVALID_BUFFER_SIZE.
One convenient use of buf.swap16()
is to perform a fast in-place conversion
between UTF-16 little-endian and UTF-16 big-endian:
const buf = Buffer.from('This is little-endian UTF-16', 'utf16le');
buf.swap16(); // Convert to big-endian UTF-16 text.
buf.swap32()
#
- Returns: <Buffer> A reference to
buf
.
Interprets buf
as an array of unsigned 32-bit integers and swaps the
byte order in-place. Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 4.
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap32();
console.log(buf1);
// Prints: <Buffer 04 03 02 01 08 07 06 05>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap32();
// Throws ERR_INVALID_BUFFER_SIZE.
buf.swap64()
#
- Returns: <Buffer> A reference to
buf
.
Interprets buf
as an array of 64-bit numbers and swaps byte order in-place.
Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 8.
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap64();
console.log(buf1);
// Prints: <Buffer 08 07 06 05 04 03 02 01>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap64();
// Throws ERR_INVALID_BUFFER_SIZE.
buf.toJSON()
#
- Returns: <Object>
Returns a JSON representation of buf
. JSON.stringify()
implicitly calls
this function when stringifying a Buffer
instance.
Buffer.from()
accepts objects in the format returned from this method.
In particular, Buffer.from(buf.toJSON())
works like Buffer.from(buf)
.
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
console.log(json);
// Prints: {"type":"Buffer","data":[1,2,3,4,5]}
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer' ?
Buffer.from(value) :
value;
});
console.log(copy);
// Prints: <Buffer 01 02 03 04 05>
buf.toString([encoding[, start[, end]]])
#
encoding
<string> The character encoding to use. Default:'utf8'
.start
<integer> The byte offset to start decoding at. Default:0
.end
<integer> The byte offset to stop decoding at (not inclusive). Default:buf.length
.- Returns: <string>
Decodes buf
to a string according to the specified character encoding in
encoding
. start
and end
may be passed to decode only a subset of buf
.
If encoding
is 'utf8'
and a byte sequence in the input is not valid UTF-8,
then each invalid byte is replaced with the replacement character U+FFFD
.
The maximum length of a string instance (in UTF-16 code units) is available
as buffer.constants.MAX_STRING_LENGTH
.
const buf1 = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
console.log(buf1.toString('utf8'));
// Prints: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('utf8', 0, 5));
// Prints: abcde
const buf2 = Buffer.from('tést');
console.log(buf2.toString('hex'));
// Prints: 74c3a97374
console.log(buf2.toString('utf8', 0, 3));
// Prints: té
console.log(buf2.toString(undefined, 0, 3));
// Prints: té
buf.values()
#
- Returns: <Iterator>
Creates and returns an iterator for buf
values (bytes). This function is
called automatically when a Buffer
is used in a for..of
statement.
const buf = Buffer.from('buffer');
for (const value of buf.values()) {
console.log(value);
}
// Prints:
// 98
// 117
// 102
// 102
// 101
// 114
for (const value of buf) {
console.log(value);
}
// Prints:
// 98
// 117
// 102
// 102
// 101
// 114
buf.write(string[, offset[, length]][, encoding])
#
string
<string> String to write tobuf
.offset
<integer> Number of bytes to skip before starting to writestring
. Default:0
.length
<integer> Maximum number of bytes to write (written bytes will not exceedbuf.length - offset
). Default:buf.length - offset
.encoding
<string> The character encoding ofstring
. Default:'utf8'
.- Returns: <integer> Number of bytes written.
Writes string
to buf
at offset
according to the character encoding in
encoding
. The length
parameter is the number of bytes to write. If buf
did
not contain enough space to fit the entire string, only part of string
will be
written. However, partially encoded characters will not be written.
const buf = Buffer.alloc(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
// Prints: 12 bytes: ½ + ¼ = ¾
const buffer = Buffer.alloc(10);
const length = buffer.write('abcd', 8);
console.log(`${length} bytes: ${buffer.toString('utf8', 8, 10)}`);
// Prints: 2 bytes : ab
buf.writeBigInt64BE(value[, offset])
#
value
<bigint> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian.
value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(8);
buf.writeBigInt64BE(0x0102030405060708n, 0);
console.log(buf);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf.writeBigInt64LE(value[, offset])
#
value
<bigint> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian.
value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(8);
buf.writeBigInt64LE(0x0102030405060708n, 0);
console.log(buf);
// Prints: <Buffer 08 07 06 05 04 03 02 01>
buf.writeBigUInt64BE(value[, offset])
#
value
<bigint> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian.
const buf = Buffer.allocUnsafe(8);
buf.writeBigUInt64BE(0xdecafafecacefaden, 0);
console.log(buf);
// Prints: <Buffer de ca fa fe ca ce fa de>
buf.writeBigUInt64LE(value[, offset])
#
value
<bigint> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy:0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian
const buf = Buffer.allocUnsafe(8);
buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
console.log(buf);
// Prints: <Buffer de fa ce ca fe fa ca de>
buf.writeDoubleBE(value[, offset])
#
value
<number> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. The value
must be a JavaScript number. Behavior is undefined when value
is anything
other than a JavaScript number.
const buf = Buffer.allocUnsafe(8);
buf.writeDoubleBE(123.456, 0);
console.log(buf);
// Prints: <Buffer 40 5e dd 2f 1a 9f be 77>
buf.writeDoubleLE(value[, offset])
#
value
<number> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 8
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. The value
must be a JavaScript number. Behavior is undefined when value
is anything
other than a JavaScript number.
const buf = Buffer.allocUnsafe(8);
buf.writeDoubleLE(123.456, 0);
console.log(buf);
// Prints: <Buffer 77 be 9f 1a 2f dd 5e 40>
buf.writeFloatBE(value[, offset])
#
value
<number> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. Behavior is
undefined when value
is anything other than a JavaScript number.
const buf = Buffer.allocUnsafe(4);
buf.writeFloatBE(0xcafebabe, 0);
console.log(buf);
// Prints: <Buffer 4f 4a fe bb>
buf.writeFloatLE(value[, offset])
#
value
<number> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. Behavior is
undefined when value
is anything other than a JavaScript number.
const buf = Buffer.allocUnsafe(4);
buf.writeFloatLE(0xcafebabe, 0);
console.log(buf);
// Prints: <Buffer bb fe 4a 4f>
buf.writeInt8(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 1
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
. value
must be a valid
signed 8-bit integer. Behavior is undefined when value
is anything other than
a signed 8-bit integer.
value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(2);
buf.writeInt8(2, 0);
buf.writeInt8(-2, 1);
console.log(buf);
// Prints: <Buffer 02 fe>
buf.writeInt16BE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid signed 16-bit integer. Behavior is undefined when value
is
anything other than a signed 16-bit integer.
The value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(2);
buf.writeInt16BE(0x0102, 0);
console.log(buf);
// Prints: <Buffer 01 02>
buf.writeInt16LE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid signed 16-bit integer. Behavior is undefined when value
is
anything other than a signed 16-bit integer.
The value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(2);
buf.writeInt16LE(0x0304, 0);
console.log(buf);
// Prints: <Buffer 04 03>
buf.writeInt32BE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid signed 32-bit integer. Behavior is undefined when value
is
anything other than a signed 32-bit integer.
The value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(4);
buf.writeInt32BE(0x01020304, 0);
console.log(buf);
// Prints: <Buffer 01 02 03 04>
buf.writeInt32LE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid signed 32-bit integer. Behavior is undefined when value
is
anything other than a signed 32-bit integer.
The value
is interpreted and written as a two's complement signed integer.
const buf = Buffer.allocUnsafe(4);
buf.writeInt32LE(0x05060708, 0);
console.log(buf);
// Prints: <Buffer 08 07 06 05>
buf.writeIntBE(value, offset, byteLength)
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to write. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
offset
plus the number of bytes written.
Writes byteLength
bytes of value
to buf
at the specified offset
as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined when
value
is anything other than a signed integer.
const buf = Buffer.allocUnsafe(6);
buf.writeIntBE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer 12 34 56 78 90 ab>
buf.writeIntLE(value, offset, byteLength)
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to write. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
offset
plus the number of bytes written.
Writes byteLength
bytes of value
to buf
at the specified offset
as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
when value
is anything other than a signed integer.
const buf = Buffer.allocUnsafe(6);
buf.writeIntLE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer ab 90 78 56 34 12>
buf.writeUInt8(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 1
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
. value
must be a
valid unsigned 8-bit integer. Behavior is undefined when value
is anything
other than an unsigned 8-bit integer.
const buf = Buffer.allocUnsafe(4);
buf.writeUInt8(0x3, 0);
buf.writeUInt8(0x4, 1);
buf.writeUInt8(0x23, 2);
buf.writeUInt8(0x42, 3);
console.log(buf);
// Prints: <Buffer 03 04 23 42>
buf.writeUInt16BE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid unsigned 16-bit integer. Behavior is undefined when value
is anything other than an unsigned 16-bit integer.
const buf = Buffer.allocUnsafe(4);
buf.writeUInt16BE(0xdead, 0);
buf.writeUInt16BE(0xbeef, 2);
console.log(buf);
// Prints: <Buffer de ad be ef>
buf.writeUInt16LE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 2
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid unsigned 16-bit integer. Behavior is undefined when value
is
anything other than an unsigned 16-bit integer.
const buf = Buffer.allocUnsafe(4);
buf.writeUInt16LE(0xdead, 0);
buf.writeUInt16LE(0xbeef, 2);
console.log(buf);
// Prints: <Buffer ad de ef be>
buf.writeUInt32BE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid unsigned 32-bit integer. Behavior is undefined when value
is anything other than an unsigned 32-bit integer.
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32BE(0xfeedface, 0);
console.log(buf);
// Prints: <Buffer fe ed fa ce>
buf.writeUInt32LE(value[, offset])
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - 4
. Default:0
.- Returns: <integer>
offset
plus the number of bytes written.
Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid unsigned 32-bit integer. Behavior is undefined when value
is
anything other than an unsigned 32-bit integer.
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32LE(0xfeedface, 0);
console.log(buf);
// Prints: <Buffer ce fa ed fe>
buf.writeUIntBE(value, offset, byteLength)
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to write. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
offset
plus the number of bytes written.
Writes byteLength
bytes of value
to buf
at the specified offset
as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined
when value
is anything other than an unsigned integer.
const buf = Buffer.allocUnsafe(6);
buf.writeUIntBE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer 12 34 56 78 90 ab>
buf.writeUIntLE(value, offset, byteLength)
#
value
<integer> Number to be written tobuf
.offset
<integer> Number of bytes to skip before starting to write. Must satisfy0 <= offset <= buf.length - byteLength
.byteLength
<integer> Number of bytes to write. Must satisfy0 < byteLength <= 6
.- Returns: <integer>
offset
plus the number of bytes written.
Writes byteLength
bytes of value
to buf
at the specified offset
as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
when value
is anything other than an unsigned integer.
const buf = Buffer.allocUnsafe(6);
buf.writeUIntLE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer ab 90 78 56 34 12>
new Buffer(array)
#
Buffer.from(array)
instead.array
<integer[]> An array of bytes to copy from.
See Buffer.from(array)
.
new Buffer(arrayBuffer[, byteOffset[, length]])
#
Buffer.from(arrayBuffer[, byteOffset[, length]])
instead.arrayBuffer
<ArrayBuffer> | <SharedArrayBuffer> AnArrayBuffer
,SharedArrayBuffer
or the.buffer
property of aTypedArray
.byteOffset
<integer> Index of first byte to expose. Default:0
.length
<integer> Number of bytes to expose. Default:arrayBuffer.byteLength - byteOffset
.
See
Buffer.from(arrayBuffer[, byteOffset[, length]])
.
new Buffer(buffer)
#
Buffer.from(buffer)
instead.buffer
<Buffer> | <Uint8Array> An existingBuffer
orUint8Array
from which to copy data.
See Buffer.from(buffer)
.
new Buffer(size)
#
size
<integer> The desired length of the newBuffer
.
See Buffer.alloc()
and Buffer.allocUnsafe()
. This variant of the
constructor is equivalent to Buffer.alloc()
.
new Buffer(string[, encoding])
#
Buffer.from(string[, encoding])
instead.See Buffer.from(string[, encoding])
.
buffer
module APIs#
While, the Buffer
object is available as a global, there are additional
Buffer
-related APIs that are available only via the buffer
module
accessed using require('buffer')
.
buffer.INSPECT_MAX_BYTES
#
- <integer> Default:
50
Returns the maximum number of bytes that will be returned when
buf.inspect()
is called. This can be overridden by user modules. See
util.inspect()
for more details on buf.inspect()
behavior.
buffer.kMaxLength
#
- <integer> The largest size allowed for a single
Buffer
instance.
An alias for buffer.constants.MAX_LENGTH
.
buffer.transcode(source, fromEnc, toEnc)
#
source
<Buffer> | <Uint8Array> ABuffer
orUint8Array
instance.fromEnc
<string> The current encoding.toEnc
<string> To target encoding.- Returns: <Buffer>
Re-encodes the given Buffer
or Uint8Array
instance from one character
encoding to another. Returns a new Buffer
instance.
Throws if the fromEnc
or toEnc
specify invalid character encodings or if
conversion from fromEnc
to toEnc
is not permitted.
Encodings supported by buffer.transcode()
are: 'ascii'
, 'utf8'
,
'utf16le'
, 'ucs2'
, 'latin1'
, and 'binary'
.
The transcoding process will use substitution characters if a given byte sequence cannot be adequately represented in the target encoding. For instance:
const buffer = require('buffer');
const newBuf = buffer.transcode(Buffer.from('€'), 'utf8', 'ascii');
console.log(newBuf.toString('ascii'));
// Prints: '?'
Because the Euro (€
) sign is not representable in US-ASCII, it is replaced
with ?
in the transcoded Buffer
.
Class: SlowBuffer
#
Buffer.allocUnsafeSlow()
instead.See Buffer.allocUnsafeSlow()
. This was never a class in the sense that
the constructor always returned a Buffer
instance, rather than a SlowBuffer
instance.
new SlowBuffer(size)
#
Buffer.allocUnsafeSlow()
instead.size
<integer> The desired length of the newSlowBuffer
.
Buffer constants#
buffer.constants.MAX_LENGTH
#
- <integer> The largest size allowed for a single
Buffer
instance.
On 32-bit architectures, this value currently is 230 - 1 (~1GB). On 64-bit architectures, this value currently is 231 - 1 (~2GB).
This value is also available as buffer.kMaxLength
.
buffer.constants.MAX_STRING_LENGTH
#
- <integer> The largest length allowed for a single
string
instance.
Represents the largest length
that a string
primitive can have, counted
in UTF-16 code units.
This value may depend on the JS engine that is being used.
Buffer.from()
, Buffer.alloc()
, and Buffer.allocUnsafe()
#
In versions of Node.js prior to 6.0.0, Buffer
instances were created using the
Buffer
constructor function, which allocates the returned Buffer
differently based on what arguments are provided:
- Passing a number as the first argument to
Buffer()
(e.g.new Buffer(10)
) allocates a newBuffer
object of the specified size. Prior to Node.js 8.0.0, the memory allocated for suchBuffer
instances is not initialized and can contain sensitive data. SuchBuffer
instances must be subsequently initialized by using eitherbuf.fill(0)
or by writing to the entireBuffer
before reading data from theBuffer
. While this behavior is intentional to improve performance, development experience has demonstrated that a more explicit distinction is required between creating a fast-but-uninitializedBuffer
versus creating a slower-but-saferBuffer
. Since Node.js 8.0.0,Buffer(num)
andnew Buffer(num)
return aBuffer
with initialized memory. - Passing a string, array, or
Buffer
as the first argument copies the passed object's data into theBuffer
. - Passing an
ArrayBuffer
or aSharedArrayBuffer
returns aBuffer
that shares allocated memory with the given array buffer.
Because the behavior of new Buffer()
is different depending on the type of the
first argument, security and reliability issues can be inadvertently introduced
into applications when argument validation or Buffer
initialization is not
performed.
For example, if an attacker can cause an application to receive a number where
a string is expected, the application may call new Buffer(100)
instead of new Buffer("100")
, leading it to allocate a 100 byte buffer instead
of allocating a 3 byte buffer with content "100"
. This is commonly possible
using JSON API calls. Since JSON distinguishes between numeric and string types,
it allows injection of numbers where a naively written application that does not
validate its input sufficiently might expect to always receive a string.
Before Node.js 8.0.0, the 100 byte buffer might contain
arbitrary pre-existing in-memory data, so may be used to expose in-memory
secrets to a remote attacker. Since Node.js 8.0.0, exposure of memory cannot
occur because the data is zero-filled. However, other attacks are still
possible, such as causing very large buffers to be allocated by the server,
leading to performance degradation or crashing on memory exhaustion.
To make the creation of Buffer
instances more reliable and less error-prone,
the various forms of the new Buffer()
constructor have been deprecated
and replaced by separate Buffer.from()
, Buffer.alloc()
, and
Buffer.allocUnsafe()
methods.
Developers should migrate all existing uses of the new Buffer()
constructors
to one of these new APIs.
Buffer.from(array)
returns a newBuffer
that contains a copy of the provided octets.Buffer.from(arrayBuffer[, byteOffset[, length]])
returns a newBuffer
that shares the same allocated memory as the givenArrayBuffer
.Buffer.from(buffer)
returns a newBuffer
that contains a copy of the contents of the givenBuffer
.Buffer.from(string[, encoding])
returns a newBuffer
that contains a copy of the provided string.Buffer.alloc(size[, fill[, encoding]])
returns a new initializedBuffer
of the specified size. This method is slower thanBuffer.allocUnsafe(size)
but guarantees that newly createdBuffer
instances never contain old data that is potentially sensitive. ATypeError
will be thrown ifsize
is not a number.Buffer.allocUnsafe(size)
andBuffer.allocUnsafeSlow(size)
each return a new uninitializedBuffer
of the specifiedsize
. Because theBuffer
is uninitialized, the allocated segment of memory might contain old data that is potentially sensitive.
Buffer
instances returned by Buffer.allocUnsafe()
and
Buffer.from(array)
may be allocated off a shared internal memory pool
if size
is less than or equal to half Buffer.poolSize
. Instances
returned by Buffer.allocUnsafeSlow()
never use the shared internal
memory pool.
The --zero-fill-buffers
command line option#
Node.js can be started using the --zero-fill-buffers
command line option to
cause all newly-allocated Buffer
instances to be zero-filled upon creation by
default. Without the option, buffers created with Buffer.allocUnsafe()
,
Buffer.allocUnsafeSlow()
, and new SlowBuffer(size)
are not zero-filled.
Use of this flag can have a measurable negative impact on performance. Use the
--zero-fill-buffers
option only when necessary to enforce that newly allocated
Buffer
instances cannot contain old data that is potentially sensitive.
$ node --zero-fill-buffers
> Buffer.allocUnsafe(5);
<Buffer 00 00 00 00 00>
What makes Buffer.allocUnsafe()
and Buffer.allocUnsafeSlow()
"unsafe"?#
When calling Buffer.allocUnsafe()
and Buffer.allocUnsafeSlow()
, the
segment of allocated memory is uninitialized (it is not zeroed-out). While
this design makes the allocation of memory quite fast, the allocated segment of
memory might contain old data that is potentially sensitive. Using a Buffer
created by Buffer.allocUnsafe()
without completely overwriting the
memory can allow this old data to be leaked when the Buffer
memory is read.
While there are clear performance advantages to using
Buffer.allocUnsafe()
, extra care must be taken in order to avoid
introducing security vulnerabilities into an application.
C++ addons#
Addons are dynamically-linked shared objects written in C++. The
require()
function can load addons as ordinary Node.js modules.
Addons provide an interface between JavaScript and C/C++ libraries.
There are three options for implementing addons: N-API, nan, or direct use of internal V8, libuv and Node.js libraries. Unless there is a need for direct access to functionality which is not exposed by N-API, use N-API. Refer to C/C++ addons with N-API for more information on N-API.
When not using N-API, implementing addons is complicated, involving knowledge of several components and APIs:
-
V8: the C++ library Node.js uses to provide the JavaScript implementation. V8 provides the mechanisms for creating objects, calling functions, etc. V8's API is documented mostly in the
v8.h
header file (deps/v8/include/v8.h
in the Node.js source tree), which is also available online. -
libuv: The C library that implements the Node.js event loop, its worker threads and all of the asynchronous behaviors of the platform. It also serves as a cross-platform abstraction library, giving easy, POSIX-like access across all major operating systems to many common system tasks, such as interacting with the filesystem, sockets, timers, and system events. libuv also provides a pthreads-like threading abstraction that may be used to power more sophisticated asynchronous addons that need to move beyond the standard event loop. Addon authors are encouraged to think about how to avoid blocking the event loop with I/O or other time-intensive tasks by off-loading work via libuv to non-blocking system operations, worker threads or a custom use of libuv's threads.
-
Internal Node.js libraries. Node.js itself exports C++ APIs that addons can use, the most important of which is the
node::ObjectWrap
class. -
Node.js includes other statically linked libraries including OpenSSL. These other libraries are located in the
deps/
directory in the Node.js source tree. Only the libuv, OpenSSL, V8 and zlib symbols are purposefully re-exported by Node.js and may be used to various extents by addons. See Linking to libraries included with Node.js for additional information.
All of the following examples are available for download and may be used as the starting-point for an addon.
Hello world#
This "Hello world" example is a simple addon, written in C++, that is the equivalent of the following JavaScript code:
module.exports.hello = () => 'world';
First, create the file hello.cc
:
// hello.cc
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(
isolate, "world", NewStringType::kNormal).ToLocalChecked());
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
} // namespace demo
All Node.js addons must export an initialization function following the pattern:
void Initialize(Local<Object> exports);
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
There is no semi-colon after NODE_MODULE
as it's not a function (see
node.h
).
The module_name
must match the filename of the final binary (excluding
the .node
suffix).
In the hello.cc
example, then, the initialization function is Initialize
and the addon module name is addon
.
When building addons with node-gyp
, using the macro NODE_GYP_MODULE_NAME
as
the first parameter of NODE_MODULE()
will ensure that the name of the final
binary will be passed to NODE_MODULE()
.
Context-aware addons#
There are environments in which Node.js addons may need to be loaded multiple
times in multiple contexts. For example, the Electron runtime runs multiple
instances of Node.js in a single process. Each instance will have its own
require()
cache, and thus each instance will need a native addon to behave
correctly when loaded via require()
. From the addon's perspective, this means
that it must support multiple initializations.
A context-aware addon can be constructed by using the macro
NODE_MODULE_INITIALIZER
, which expands to the name of a function which Node.js
will expect to find when it loads an addon. An addon can thus be initialized as
in the following example:
using namespace v8;
extern "C" NODE_MODULE_EXPORT void
NODE_MODULE_INITIALIZER(Local<Object> exports,
Local<Value> module,
Local<Context> context) {
/* Perform addon initialization steps here. */
}
Another option is to use the macro NODE_MODULE_INIT()
, which will also
construct a context-aware addon. Unlike NODE_MODULE()
, which is used to
construct an addon around a given addon initializer function,
NODE_MODULE_INIT()
serves as the declaration of such an initializer to be
followed by a function body.
The following three variables may be used inside the function body following an
invocation of NODE_MODULE_INIT()
:
Local<Object> exports
,Local<Value> module
, andLocal<Context> context
The choice to build a context-aware addon carries with it the responsibility of carefully managing global static data. Since the addon may be loaded multiple times, potentially even from different threads, any global static data stored in the addon must be properly protected, and must not contain any persistent references to JavaScript objects. The reason for this is that JavaScript objects are only valid in one context, and will likely cause a crash when accessed from the wrong context or from a different thread than the one on which they were created.
The context-aware addon can be structured to avoid global static data by performing the following steps:
- Define a class which will hold per-addon-instance data and which has a static
member of the form
static void DeleteInstance(void* data) { // Cast `data` to an instance of the class and delete it. }
- Heap-allocate an instance of this class in the addon initializer. This can be
accomplished using the
new
keyword. - Call
node::AddEnvironmentCleanupHook()
, passing it the above-created instance and a pointer toDeleteInstance()
. This will ensure the instance is deleted when the environment is torn down. - Store the instance of the class in a
v8::External
, and - Pass the
v8::External
to all methods exposed to JavaScript by passing it tov8::FunctionTemplate::New()
orv8::Function::New()
which creates the native-backed JavaScript functions. The third parameter ofv8::FunctionTemplate::New()
orv8::Function::New()
accepts thev8::External
and makes it available in the native callback using thev8::FunctionCallbackInfo::Data()
method.
This will ensure that the per-addon-instance data reaches each binding that can be called from JavaScript. The per-addon-instance data must also be passed into any asynchronous callbacks the addon may create.
The following example illustrates the implementation of a context-aware addon:
#include <node.h>
using namespace v8;
class AddonData {
public:
explicit AddonData(Isolate* isolate):
call_count(0) {
// Ensure this per-addon-instance data is deleted at environment cleanup.
node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this);
}
// Per-addon data.
int call_count;
static void DeleteInstance(void* data) {
delete static_cast<AddonData*>(data);
}
};
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
// Retrieve the per-addon-instance data.
AddonData* data =
reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
data->call_count++;
info.GetReturnValue().Set((double)data->call_count);
}
// Initialize this addon to be context-aware.
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();
// Create a new instance of `AddonData` for this instance of the addon and
// tie its life cycle to that of the Node.js environment.
AddonData* data = new AddonData(isolate);
// Wrap the data in a `v8::External` so we can pass it to the method we
// expose.
Local<External> external = External::New(isolate, data);
// Expose the method `Method` to JavaScript, and make sure it receives the
// per-addon-instance data we created above by passing `external` as the
// third parameter to the `FunctionTemplate` constructor.
exports->Set(context,
String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, Method, external)
->GetFunction(context).ToLocalChecked()).FromJust();
}
Worker support#
In order to be loaded from multiple Node.js environments, such as a main thread and a Worker thread, an add-on needs to either:
- Be an N-API addon, or
- Be declared as context-aware using
NODE_MODULE_INIT()
as described above
In order to support Worker
threads, addons need to clean up any resources
they may have allocated when such a thread exists. This can be achieved through
the usage of the AddEnvironmentCleanupHook()
function:
void AddEnvironmentCleanupHook(v8::Isolate* isolate,
void (*fun)(void* arg),
void* arg);
This function adds a hook that will run before a given Node.js instance shuts
down. If necessary, such hooks can be removed before they are run using
RemoveEnvironmentCleanupHook()
, which has the same signature. Callbacks are
run in last-in first-out order.
If necessary, there is an additional pair of AddEnvironmentCleanupHook()
and RemoveEnvironmentCleanupHook()
overloads, where the cleanup hook takes a
callback function. This can be used for shutting down asynchronous resources,
such as any libuv handles registered by the addon.
The following addon.cc
uses AddEnvironmentCleanupHook
:
// addon.cc
#include <assert.h>
#include <stdlib.h>
#include <node.h>
using node::AddEnvironmentCleanupHook;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
// Note: In a real-world application, do not rely on static/global data.
static char cookie[] = "yum yum";
static int cleanup_cb1_called = 0;
static int cleanup_cb2_called = 0;
static void cleanup_cb1(void* arg) {
Isolate* isolate = static_cast<Isolate*>(arg);
HandleScope scope(isolate);
Local<Object> obj = Object::New(isolate);
assert(!obj.IsEmpty()); // assert VM is still alive
assert(obj->IsObject());
cleanup_cb1_called++;
}
static void cleanup_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
cleanup_cb2_called++;
}
static void sanity_check(void*) {
assert(cleanup_cb1_called == 1);
assert(cleanup_cb2_called == 1);
}
// Initialize this addon to be context-aware.
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();
AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
}
Test in JavaScript by running:
// test.js
require('./build/Release/addon');
Building#
Once the source code has been written, it must be compiled into the binary
addon.node
file. To do so, create a file called binding.gyp
in the
top-level of the project describing the build configuration of the module
using a JSON-like format. This file is used by node-gyp, a tool written
specifically to compile Node.js addons.
{
"targets": [
{
"target_name": "addon",
"sources": [ "hello.cc" ]
}
]
}
A version of the node-gyp
utility is bundled and distributed with
Node.js as part of npm
. This version is not made directly available for
developers to use and is intended only to support the ability to use the
npm install
command to compile and install addons. Developers who wish to
use node-gyp
directly can install it using the command
npm install -g node-gyp
. See the node-gyp
installation instructions for
more information, including platform-specific requirements.
Once the binding.gyp
file has been created, use node-gyp configure
to
generate the appropriate project build files for the current platform. This
will generate either a Makefile
(on Unix platforms) or a vcxproj
file
(on Windows) in the build/
directory.
Next, invoke the node-gyp build
command to generate the compiled addon.node
file. This will be put into the build/Release/
directory.
When using npm install
to install a Node.js addon, npm uses its own bundled
version of node-gyp
to perform this same set of actions, generating a
compiled version of the addon for the user's platform on demand.
Once built, the binary addon can be used from within Node.js by pointing
require()
to the built addon.node
module:
// hello.js
const addon = require('./build/Release/addon');
console.log(addon.hello());
// Prints: 'world'
Because the exact path to the compiled addon binary can vary depending on how
it is compiled (i.e. sometimes it may be in ./build/Debug/
), addons can use
the bindings package to load the compiled module.
While the bindings
package implementation is more sophisticated in how it
locates addon modules, it is essentially using a try…catch
pattern similar to:
try {
return require('./build/Release/addon.node');
} catch (err) {
return require('./build/Debug/addon.node');
}
Linking to libraries included with Node.js#
Node.js uses statically linked libraries such as V8, libuv and OpenSSL. All
addons are required to link to V8 and may link to any of the other dependencies
as well. Typically, this is as simple as including the appropriate
#include <...>
statements (e.g. #include <v8.h>
) and node-gyp
will locate
the appropriate headers automatically. However, there are a few caveats to be
aware of:
-
When
node-gyp
runs, it will detect the specific release version of Node.js and download either the full source tarball or just the headers. If the full source is downloaded, addons will have complete access to the full set of Node.js dependencies. However, if only the Node.js headers are downloaded, then only the symbols exported by Node.js will be available. -
node-gyp
can be run using the--nodedir
flag pointing at a local Node.js source image. Using this option, the addon will have access to the full set of dependencies.
Loading addons using require()
#
The filename extension of the compiled addon binary is .node
(as opposed
to .dll
or .so
). The require()
function is written to look for
files with the .node
file extension and initialize those as dynamically-linked
libraries.
When calling require()
, the .node
extension can usually be
omitted and Node.js will still find and initialize the addon. One caveat,
however, is that Node.js will first attempt to locate and load modules or
JavaScript files that happen to share the same base name. For instance, if
there is a file addon.js
in the same directory as the binary addon.node
,
then require('addon')
will give precedence to the addon.js
file
and load it instead.
Native abstractions for Node.js#
Each of the examples illustrated in this document directly use the Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed dramatically from one V8 release to the next (and one major Node.js release to the next). With each change, addons may need to be updated and recompiled in order to continue functioning. The Node.js release schedule is designed to minimize the frequency and impact of such changes but there is little that Node.js can do to ensure stability of the V8 APIs.
The Native Abstractions for Node.js (or nan
) provide a set of tools that
addon developers are recommended to use to keep compatibility between past and
future releases of V8 and Node.js. See the nan
examples for an
illustration of how it can be used.
N-API#
N-API is an API for building native addons. It is independent from the underlying JavaScript runtime (e.g. V8) and is maintained as part of Node.js itself. This API will be Application Binary Interface (ABI) stable across versions of Node.js. It is intended to insulate addons from changes in the underlying JavaScript engine and allow modules compiled for one version to run on later versions of Node.js without recompilation. Addons are built/packaged with the same approach/tools outlined in this document (node-gyp, etc.). The only difference is the set of APIs that are used by the native code. Instead of using the V8 or Native Abstractions for Node.js APIs, the functions available in the N-API are used.
Creating and maintaining an addon that benefits from the ABI stability provided by N-API carries with it certain implementation considerations.
To use N-API in the above "Hello world" example, replace the content of
hello.cc
with the following. All other instructions remain the same.
// hello.cc using N-API
#include <node_api.h>
namespace demo {
napi_value Method(napi_env env, napi_callback_info args) {
napi_value greeting;
napi_status status;
status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
if (status != napi_ok) return nullptr;
return greeting;
}
napi_value init(napi_env env, napi_value exports) {
napi_status status;
napi_value fn;
status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
if (status != napi_ok) return nullptr;
status = napi_set_named_property(env, exports, "hello", fn);
if (status != napi_ok) return nullptr;
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
} // namespace demo
The functions available and how to use them are documented in C/C++ addons with N-API.
Addon examples#
Following are some example addons intended to help developers get started. The examples use the V8 APIs. Refer to the online V8 reference for help with the various V8 calls, and V8's Embedder's Guide for an explanation of several concepts used such as handles, scopes, function templates, etc.
Each of these examples using the following binding.gyp
file:
{
"targets": [
{
"target_name": "addon",
"sources": [ "addon.cc" ]
}
]
}
In cases where there is more than one .cc
file, simply add the additional
filename to the sources
array:
"sources": ["addon.cc", "myexample.cc"]
Once the binding.gyp
file is ready, the example addons can be configured and
built using node-gyp
:
$ node-gyp configure build
Function arguments#
Addons will typically expose objects and functions that can be accessed from JavaScript running within Node.js. When functions are invoked from JavaScript, the input arguments and return value must be mapped to and from the C/C++ code.
The following example illustrates how to read function arguments passed from JavaScript and how to return a result:
// addon.cc
#include <node.h>
namespace demo {
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
// This is the implementation of the "add" method
// Input arguments are passed using the
// const FunctionCallbackInfo<Value>& args struct
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
// Check the number of arguments passed.
if (args.Length() < 2) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate,
"Wrong number of arguments",
NewStringType::kNormal).ToLocalChecked()));
return;
}
// Check the argument types
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate,
"Wrong arguments",
NewStringType::kNormal).ToLocalChecked()));
return;
}
// Perform the operation
double value =
args[0].As<Number>()->Value() + args[1].As<Number>()->Value();
Local<Number> num = Number::New(isolate, value);
// Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
args.GetReturnValue().Set(num);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
Once compiled, the example addon can be required and used from within Node.js:
// test.js
const addon = require('./build/Release/addon');
console.log('This should be eight:', addon.add(3, 5));
Callbacks#
It is common practice within addons to pass JavaScript functions to a C++ function and execute them from there. The following example illustrates how to invoke such callbacks:
// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
void RunCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[argc] = {
String::NewFromUtf8(isolate,
"hello world",
NewStringType::kNormal).ToLocalChecked() };
cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", RunCallback);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
This example uses a two-argument form of Init()
that receives the full
module
object as the second argument. This allows the addon to completely
overwrite exports
with a single function instead of adding the function as a
property of exports
.
To test it, run the following JavaScript:
// test.js
const addon = require('./build/Release/addon');
addon((msg) => {
console.log(msg);
// Prints: 'hello world'
});
In this example, the callback function is invoked synchronously.
Object factory#
Addons can create and return new objects from within a C++ function as
illustrated in the following example. An object is created and returned with a
property msg
that echoes the string passed to createObject()
:
// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Object> obj = Object::New(isolate);
obj->Set(context,
String::NewFromUtf8(isolate,
"msg",
NewStringType::kNormal).ToLocalChecked(),
args[0]->ToString(context).ToLocalChecked())
.FromJust();
args.GetReturnValue().Set(obj);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
To test it in JavaScript:
// test.js
const addon = require('./build/Release/addon');
const obj1 = addon('hello');
const obj2 = addon('world');
console.log(obj1.msg, obj2.msg);
// Prints: 'hello world'
Function factory#
Another common scenario is creating JavaScript functions that wrap C++ functions and returning those back to JavaScript:
// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void MyFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(
isolate, "hello world", NewStringType::kNormal).ToLocalChecked());
}
void CreateFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
Local<Function> fn = tpl->GetFunction(context).ToLocalChecked();
// omit this to make it anonymous
fn->SetName(String::NewFromUtf8(
isolate, "theFunction", NewStringType::kNormal).ToLocalChecked());
args.GetReturnValue().Set(fn);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateFunction);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
To test:
// test.js
const addon = require('./build/Release/addon');
const fn = addon();
console.log(fn());
// Prints: 'hello world'
Wrapping C++ objects#
It is also possible to wrap C++ objects/classes in a way that allows new
instances to be created using the JavaScript new
operator:
// addon.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Local;
using v8::Object;
void InitAll(Local<Object> exports) {
MyObject::Init(exports);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
Then, in myobject.h
, the wrapper class inherits from node::ObjectWrap
:
// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
double value_;
};
} // namespace demo
#endif
In myobject.cc
, implement the various methods that are to be exposed.
Below, the method plusOne()
is exposed by adding it to the constructor's
prototype:
// myobject.cc
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
using v8::String;
using v8::Value;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Local<Object> exports) {
Isolate* isolate = exports->GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::New(isolate);
addon_data_tpl->SetInternalFieldCount(1); // 1 field for the MyObject::New()
Local<Object> addon_data =
addon_data_tpl->NewInstance(context).ToLocalChecked();
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New, addon_data);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
Local<Function> constructor = tpl->GetFunction(context).ToLocalChecked();
addon_data->SetInternalField(0, constructor);
exports->Set(context, String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(),
constructor).FromJust();
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons =
args.Data().As<Object>()->GetInternalField(0).As<Function>();
Local<Object> result =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(result);
}
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo
To build this example, the myobject.cc
file must be added to the
binding.gyp
:
{
"targets": [
{
"target_name": "addon",
"sources": [
"addon.cc",
"myobject.cc"
]
}
]
}
Test it with:
// test.js
const addon = require('./build/Release/addon');
const obj = new addon.MyObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13
The destructor for a wrapper object will run when the object is garbage-collected. For destructor testing, there are command-line flags that can be used to make it possible to force garbage collection. These flags are provided by the underlying V8 JavaScript engine. They are subject to change or removal at any time. They are not documented by Node.js or V8, and they should never be used outside of testing.
Factory of wrapped objects#
Alternatively, it is possible to use a factory pattern to avoid explicitly
creating object instances using the JavaScript new
operator:
const obj = addon.createObject();
// instead of:
// const obj = new addon.Object();
First, the createObject()
method is implemented in addon.cc
:
// addon.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void InitAll(Local<Object> exports, Local<Object> module) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
In myobject.h
, the static method NewInstance()
is added to handle
instantiating the object. This method takes the place of using new
in
JavaScript:
// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Global<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif
The implementation in myobject.cc
is similar to the previous example:
// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using node::AddEnvironmentCleanupHook;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Global;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
// Warning! This is not thread-safe, this addon cannot be used for worker
// threads.
Global<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
Local<Context> context = isolate->GetCurrentContext();
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
AddEnvironmentCleanupHook(isolate, [](void*) {
constructor.Reset();
}, nullptr);
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo
Once again, to build this example, the myobject.cc
file must be added to the
binding.gyp
:
{
"targets": [
{
"target_name": "addon",
"sources": [
"addon.cc",
"myobject.cc"
]
}
]
}
Test it with:
// test.js
const createObject = require('./build/Release/addon');
const obj = createObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13
const obj2 = createObject(20);
console.log(obj2.plusOne());
// Prints: 21
console.log(obj2.plusOne());
// Prints: 22
console.log(obj2.plusOne());
// Prints: 23
Passing wrapped objects around#
In addition to wrapping and returning C++ objects, it is possible to pass
wrapped objects around by unwrapping them with the Node.js helper function
node::ObjectWrap::Unwrap
. The following examples shows a function add()
that can take two MyObject
objects as input arguments:
// addon.cc
#include <node.h>
#include <node_object_wrap.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
args[0]->ToObject(context).ToLocalChecked());
MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
args[1]->ToObject(context).ToLocalChecked());
double sum = obj1->value() + obj2->value();
args.GetReturnValue().Set(Number::New(isolate, sum));
}
void InitAll(Local<Object> exports) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(exports, "createObject", CreateObject);
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
In myobject.h
, a new public method is added to allow access to private values
after unwrapping the object.
// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
inline double value() const { return value_; }
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Global<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif
The implementation of myobject.cc
is similar to before:
// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using node::AddEnvironmentCleanupHook;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Global;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
// Warning! This is not thread-safe, this addon cannot be used for worker
// threads.
Global<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Context> context = isolate->GetCurrentContext();
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
AddEnvironmentCleanupHook(isolate, [](void*) {
constructor.Reset();
}, nullptr);
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
} // namespace demo
Test it with:
// test.js
const addon = require('./build/Release/addon');
const obj1 = addon.createObject(10);
const obj2 = addon.createObject(20);
const result = addon.add(obj1, obj2);
console.log(result);
// Prints: 30
N-API#
N-API (pronounced N as in the letter, followed by API) is an API for building native Addons. It is independent from the underlying JavaScript runtime (for example, V8) and is maintained as part of Node.js itself. This API will be Application Binary Interface (ABI) stable across versions of Node.js. It is intended to insulate Addons from changes in the underlying JavaScript engine and allow modules compiled for one major version to run on later major versions of Node.js without recompilation. The ABI Stability guide provides a more in-depth explanation.
Addons are built/packaged with the same approach/tools outlined in the section titled C++ Addons. The only difference is the set of APIs that are used by the native code. Instead of using the V8 or Native Abstractions for Node.js APIs, the functions available in the N-API are used.
APIs exposed by N-API are generally used to create and manipulate JavaScript values. Concepts and operations generally map to ideas specified in the ECMA-262 Language Specification. The APIs have the following properties:
- All N-API calls return a status code of type
napi_status
. This status indicates whether the API call succeeded or failed. - The API's return value is passed via an out parameter.
- All JavaScript values are abstracted behind an opaque type named
napi_value
. - In case of an error status code, additional information can be obtained
using
napi_get_last_error_info
. More information can be found in the error handling section Error handling.
The N-API is a C API that ensures ABI stability across Node.js versions
and different compiler levels. A C++ API can be easier to use.
To support using C++, the project maintains a
C++ wrapper module called node-addon-api
.
This wrapper provides an inlineable C++ API. Binaries built
with node-addon-api
will depend on the symbols for the N-API C-based
functions exported by Node.js. node-addon-api
is a more
efficient way to write code that calls N-API. Take, for example, the
following node-addon-api
code. The first section shows the
node-addon-api
code and the second section shows what actually gets
used in the addon.
Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");
napi_status status;
napi_value object, string;
status = napi_create_object(env, &object);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_set_named_property(env, object, "foo", string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
The end result is that the addon only uses the exported C APIs. As a result, it still gets the benefits of the ABI stability provided by the C API.
When using node-addon-api
instead of the C APIs, start with the API docs
for node-addon-api
.
The N-API Resource offers an
excellent orientation and tips for developers just getting started with N-API
and node-addon-api
.
Implications of ABI stability#
Although N-API provides an ABI stability guarantee, other parts of Node.js do not, and any external libraries used from the addon may not. In particular, none of the following APIs provide an ABI stability guarantee across major versions:
-
the Node.js C++ APIs available via any of
#include <node.h> #include <node_buffer.h> #include <node_version.h> #include <node_object_wrap.h>
-
the libuv APIs which are also included with Node.js and available via
#include <uv.h>
-
the V8 API available via
#include <v8.h>
Thus, for an addon to remain ABI-compatible across Node.js major versions, it must use N-API exclusively by restricting itself to using
#include <node_api.h>
and by checking, for all external libraries that it uses, that the external library makes ABI stability guarantees similar to N-API.
Building#
Unlike modules written in JavaScript, developing and deploying Node.js native addons using N-API requires an additional set of tools. Besides the basic tools required to develop for Node.js, the native addon developer requires a toolchain that can compile C and C++ code into a binary. In addition, depending upon how the native addon is deployed, the user of the native addon will also need to have a C/C++ toolchain installed.
For Linux developers, the necessary C/C++ toolchain packages are readily available. GCC is widely used in the Node.js community to build and test across a variety of platforms. For many developers, the LLVM compiler infrastructure is also a good choice.
For Mac developers, Xcode offers all the required compiler tools. However, it is not necessary to install the entire Xcode IDE. The following command installs the necessary toolchain:
xcode-select --install
For Windows developers, Visual Studio offers all the required compiler tools. However, it is not necessary to install the entire Visual Studio IDE. The following command installs the necessary toolchain:
npm install --global windows-build-tools
The sections below describe the additional tools available for developing and deploying Node.js native addons.
Build tools#
Both the tools listed here require that users of the native addon have a C/C++ toolchain installed in order to successfully install the native addon.
node-gyp#
node-gyp is a build system based on Google's GYP tool and comes bundled with npm. GYP, and therefore node-gyp, requires that Python be installed.
Historically, node-gyp has been the tool of choice for building native addons. It has widespread adoption and documentation. However, some developers have run into limitations in node-gyp.
CMake.js#
CMake.js is an alternative build system based on CMake.
CMake.js is a good choice for projects that already use CMake or for developers affected by limitations in node-gyp.
Uploading precompiled binaries#
The three tools listed here permit native addon developers and maintainers to create and upload binaries to public or private servers. These tools are typically integrated with CI/CD build systems like Travis CI and AppVeyor to build and upload binaries for a variety of platforms and architectures. These binaries are then available for download by users who do not need to have a C/C++ toolchain installed.
node-pre-gyp#
node-pre-gyp is a tool based on node-gyp that adds the ability to upload binaries to a server of the developer's choice. node-pre-gyp has particularly good support for uploading binaries to Amazon S3.
prebuild#
prebuild is a tool that supports builds using either node-gyp or CMake.js. Unlike node-pre-gyp which supports a variety of servers, prebuild uploads binaries only to GitHub releases. prebuild is a good choice for GitHub projects using CMake.js.
prebuildify#
prebuildify is a tool based on node-gyp. The advantage of prebuildify is that the built binaries are bundled with the native module when it's uploaded to npm. The binaries are downloaded from npm and are immediately available to the module user when the native module is installed.
Usage#
In order to use the N-API functions, include the file node_api.h
which is
located in the src directory in the node development tree:
#include <node_api.h>
This will opt into the default NAPI_VERSION
for the given release of Node.js.
In order to ensure compatibility with specific versions of N-API, the version
can be specified explicitly when including the header:
#define NAPI_VERSION 3
#include <node_api.h>
This restricts the N-API surface to just the functionality that was available in the specified (and earlier) versions.
Some of the N-API surface is experimental and requires explicit opt-in:
#define NAPI_EXPERIMENTAL
#include <node_api.h>
In this case the entire API surface, including any experimental APIs, will be available to the module code.
N-API version matrix#
N-API versions are additive and versioned independently from Node.js. Version 4 is an extension to version 3 in that it has all of the APIs from version 3 with some additions. This means that it is not necessary to recompile for new versions of Node.js which are listed as supporting a later version.
1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|
v6.x | v6.14.2* | |||||
v8.x | v8.0.0* | v8.10.0* | v8.11.2 | v8.16.0 | ||
v9.x | v9.0.0* | v9.3.0* | v9.11.0* | |||
v10.x | v10.0.0 | v10.0.0 | v10.0.0 | v10.16.0 | v10.17.0 | v10.20.0 |
v11.x | v11.0.0 | v11.0.0 | v11.0.0 | v11.8.0 | ||
v12.x | v12.0.0 | v12.0.0 | v12.0.0 | v12.0.0 | v12.11.0 | v12.17.0 |
v13.x | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | |
v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 |
* Indicates that the N-API version was released as experimental
Each API documented for N-API will have a header named added in:
, and APIs
which are stable will have the additional header N-API version:
.
APIs are directly usable when using a Node.js version which supports
the N-API version shown in N-API version:
or higher.
When using a Node.js version that does not support the
N-API version:
listed or if there is no N-API version:
listed,
then the API will only be available if
#define NAPI_EXPERIMENTAL
precedes the inclusion of node_api.h
or js_native_api.h
. If an API appears not to be available on
a version of Node.js which is later than the one shown in added in:
then
this is most likely the reason for the apparent absence.
The N-APIs associated strictly with accessing ECMAScript features from native
code can be found separately in js_native_api.h
and js_native_api_types.h
.
The APIs defined in these headers are included in node_api.h
and
node_api_types.h
. The headers are structured in this way in order to allow
implementations of N-API outside of Node.js. For those implementations the
Node.js specific APIs may not be applicable.
The Node.js-specific parts of an addon can be separated from the code that
exposes the actual functionality to the JavaScript environment so that the
latter may be used with multiple implementations of N-API. In the example below,
addon.c
and addon.h
refer only to js_native_api.h
. This ensures that
addon.c
can be reused to compile against either the Node.js implementation of
N-API or any implementation of N-API outside of Node.js.
addon_node.c
is a separate file that contains the Node.js specific entry point
to the addon and which instantiates the addon by calling into addon.c
when the
addon is loaded into a Node.js environment.
// addon.h
#ifndef _ADDON_H_
#define _ADDON_H_
#include <js_native_api.h>
napi_value create_addon(napi_env env);
#endif // _ADDON_H_
// addon.c
#include "addon.h"
#define NAPI_CALL(env, call) \
do { \
napi_status status = (call); \
if (status != napi_ok) { \
const napi_extended_error_info* error_info = NULL; \
napi_get_last_error_info((env), &error_info); \
bool is_pending; \
napi_is_exception_pending((env), &is_pending); \
if (!is_pending) { \
const char* message = (error_info->error_message == NULL) \
? "empty error message" \
: error_info->error_message; \
napi_throw_error((env), NULL, message); \
return NULL; \
} \
} \
} while(0)
static napi_value
DoSomethingUseful(napi_env env, napi_callback_info info) {
// Do something useful.
return NULL;
}
napi_value create_addon(napi_env env) {
napi_value result;
NAPI_CALL(env, napi_create_object(env, &result));
napi_value exported_function;
NAPI_CALL(env, napi_create_function(env,
"doSomethingUseful",
NAPI_AUTO_LENGTH,
DoSomethingUseful,
NULL,
&exported_function));
NAPI_CALL(env, napi_set_named_property(env,
result,
"doSomethingUseful",
exported_function));
return result;
}
// addon_node.c
#include <node_api.h>
#include "addon.h"
NAPI_MODULE_INIT() {
// This function body is expected to return a `napi_value`.
// The variables `napi_env env` and `napi_value exports` may be used within
// the body, as they are provided by the definition of `NAPI_MODULE_INIT()`.
return create_addon(env);
}
Environment life cycle APIs#
Section 8.7 of the ECMAScript Language Specification defines the concept of an "Agent" as a self-contained environment in which JavaScript code runs. Multiple such Agents may be started and terminated either concurrently or in sequence by the process.
A Node.js environment corresponds to an ECMAScript Agent. In the main process, an environment is created at startup, and additional environments can be created on separate threads to serve as worker threads. When Node.js is embedded in another application, the main thread of the application may also construct and destroy a Node.js environment multiple times during the life cycle of the application process such that each Node.js environment created by the application may, in turn, during its life cycle create and destroy additional environments as worker threads.
From the perspective of a native addon this means that the bindings it provides may be called multiple times, from multiple contexts, and even concurrently from multiple threads.
Native addons may need to allocate global state which they use during their entire life cycle such that the state must be unique to each instance of the addon.
To this end, N-API provides a way to allocate data such that its life cycle is tied to the life cycle of the Agent.
napi_set_instance_data#
napi_status napi_set_instance_data(napi_env env,
void* data,
napi_finalize finalize_cb,
void* finalize_hint);
[in] env
: The environment that the N-API call is invoked under.[in] data
: The data item to make available to bindings of this instance.[in] finalize_cb
: The function to call when the environment is being torn down. The function receivesdata
so that it might free it.napi_finalize
provides more details.[in] finalize_hint
: Optional hint to pass to the finalize callback during collection.
Returns napi_ok
if the API succeeded.
This API associates data
with the currently running Agent. data
can later
be retrieved using napi_get_instance_data()
. Any existing data associated with
the currently running Agent which was set by means of a previous call to
napi_set_instance_data()
will be overwritten. If a finalize_cb
was provided
by the previous call, it will not be called.
napi_get_instance_data#
napi_status napi_get_instance_data(napi_env env,
void** data);
[in] env
: The environment that the N-API call is invoked under.[out] data
: The data item that was previously associated with the currently running Agent by a call tonapi_set_instance_data()
.
Returns napi_ok
if the API succeeded.
This API retrieves data that was previously associated with the currently
running Agent via napi_set_instance_data()
. If no data is set, the call will
succeed and data
will be set to NULL
.
Basic N-API data types#
N-API exposes the following fundamental datatypes as abstractions that are consumed by the various APIs. These APIs should be treated as opaque, introspectable only with other N-API calls.
napi_status#
Integral status code indicating the success or failure of a N-API call. Currently, the following status codes are supported.
typedef enum {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
} napi_status;
If additional information is required upon an API returning a failed status,
it can be obtained by calling napi_get_last_error_info
.
napi_extended_error_info#
typedef struct {
const char* error_message;
void* engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
} napi_extended_error_info;
error_message
: UTF8-encoded string containing a VM-neutral description of the error.engine_reserved
: Reserved for VM-specific error details. This is currently not implemented for any VM.engine_error_code
: VM-specific error code. This is currently not implemented for any VM.error_code
: The N-API status code that originated with the last error.
See the Error handling section for additional information.
napi_env#
napi_env
is used to represent a context that the underlying N-API
implementation can use to persist VM-specific state. This structure is passed
to native functions when they're invoked, and it must be passed back when
making N-API calls. Specifically, the same napi_env
that was passed in when
the initial native function was called must be passed to any subsequent
nested N-API calls. Caching the napi_env
for the purpose of general reuse,
and passing the napi_env
between instances of the same addon running on
different Worker
threads is not allowed. The napi_env
becomes invalid
when an instance of a native addon is unloaded. Notification of this event is
delivered through the callbacks given to napi_add_env_cleanup_hook
and
napi_set_instance_data
.
napi_value#
This is an opaque pointer that is used to represent a JavaScript value.
napi_threadsafe_function#
This is an opaque pointer that represents a JavaScript function which can be
called asynchronously from multiple threads via
napi_call_threadsafe_function()
.
napi_threadsafe_function_release_mode#
A value to be given to napi_release_threadsafe_function()
to indicate whether
the thread-safe function is to be closed immediately (napi_tsfn_abort
) or
merely released (napi_tsfn_release
) and thus available for subsequent use via
napi_acquire_threadsafe_function()
and napi_call_threadsafe_function()
.
typedef enum {
napi_tsfn_release,
napi_tsfn_abort
} napi_threadsafe_function_release_mode;
napi_threadsafe_function_call_mode#
A value to be given to napi_call_threadsafe_function()
to indicate whether
the call should block whenever the queue associated with the thread-safe
function is full.
typedef enum {
napi_tsfn_nonblocking,
napi_tsfn_blocking
} napi_threadsafe_function_call_mode;
N-API memory management types#
napi_handle_scope#
This is an abstraction used to control and modify the lifetime of objects created within a particular scope. In general, N-API values are created within the context of a handle scope. When a native method is called from JavaScript, a default handle scope will exist. If the user does not explicitly create a new handle scope, N-API values will be created in the default handle scope. For any invocations of code outside the execution of a native method (for instance, during a libuv callback invocation), the module is required to create a scope before invoking any functions that can result in the creation of JavaScript values.
Handle scopes are created using napi_open_handle_scope
and are destroyed
using napi_close_handle_scope
. Closing the scope can indicate to the GC
that all napi_value
s created during the lifetime of the handle scope are no
longer referenced from the current stack frame.
For more details, review the Object lifetime management.
napi_escapable_handle_scope#
Escapable handle scopes are a special type of handle scope to return values created within a particular handle scope to a parent scope.
napi_ref#
This is the abstraction to use to reference a napi_value
. This allows for
users to manage the lifetimes of JavaScript values, including defining their
minimum lifetimes explicitly.
For more details, review the Object lifetime management.
napi_type_tag#
A 128-bit value stored as two unsigned 64-bit integers. It serves as a UUID
with which JavaScript objects can be "tagged" in order to ensure that they are
of a certain type. This is a stronger check than napi_instanceof
, because
the latter can report a false positive if the object's prototype has been
manipulated. Type-tagging is most useful in conjunction with napi_wrap
because it ensures that the pointer retrieved from a wrapped object can be
safely cast to the native type corresponding to the type tag that had been
previously applied to the JavaScript object.
typedef struct {
uint64_t lower;
uint64_t upper;
} napi_type_tag;
napi_async_cleanup_hook_handle#
An opaque value returned by napi_add_async_cleanup_hook
. It must be passed
to napi_remove_async_cleanup_hook
when the chain of asynchronous cleanup
events completes.
N-API callback types#
napi_callback_info#
Opaque datatype that is passed to a callback function. It can be used for getting additional information about the context in which the callback was invoked.
napi_callback#
Function pointer type for user-provided native functions which are to be exposed to JavaScript via N-API. Callback functions should satisfy the following signature:
typedef napi_value (*napi_callback)(napi_env, napi_callback_info);
Unless for reasons discussed in Object Lifetime Management, creating a
handle and/or callback scope inside a napi_callback
is not necessary.
napi_finalize#
Function pointer type for add-on provided functions that allow the user to be
notified when externally-owned data is ready to be cleaned up because the
object with which it was associated with, has been garbage-collected. The user
must provide a function satisfying the following signature which would get
called upon the object's collection. Currently, napi_finalize
can be used for
finding out when objects that have external data are collected.
typedef void (*napi_finalize)(napi_env env,
void* finalize_data,
void* finalize_hint);
Unless for reasons discussed in Object Lifetime Management, creating a handle and/or callback scope inside the function body is not necessary.
napi_async_execute_callback#
Function pointer used with functions that support asynchronous operations. Callback functions must satisfy the following signature:
typedef void (*napi_async_execute_callback)(napi_env env, void* data);
Implementations of this function must avoid making N-API calls that execute
JavaScript or interact with JavaScript objects. N-API calls should be in the
napi_async_complete_callback
instead. Do not use the napi_env
parameter as
it will likely result in execution of JavaScript.
napi_async_complete_callback#
Function pointer used with functions that support asynchronous operations. Callback functions must satisfy the following signature:
typedef void (*napi_async_complete_callback)(napi_env env,
napi_status status,
void* data);
Unless for reasons discussed in Object Lifetime Management, creating a handle and/or callback scope inside the function body is not necessary.
napi_threadsafe_function_call_js#
Function pointer used with asynchronous thread-safe function calls. The callback
will be called on the main thread. Its purpose is to use a data item arriving
via the queue from one of the secondary threads to construct the parameters
necessary for a call into JavaScript, usually via napi_call_function
, and then
make the call into JavaScript.
The data arriving from the secondary thread via the queue is given in the data
parameter and the JavaScript function to call is given in the js_callback
parameter.
N-API sets up the environment prior to calling this callback, so it is
sufficient to call the JavaScript function via napi_call_function
rather than
via napi_make_callback
.
Callback functions must satisfy the following signature:
typedef void (*napi_threadsafe_function_call_js)(napi_env env,
napi_value js_callback,
void* context,
void* data);
[in] env
: The environment to use for API calls, orNULL
if the thread-safe function is being torn down anddata
may need to be freed.[in] js_callback
: The JavaScript function to call, orNULL
if the thread-safe function is being torn down anddata
may need to be freed. It may also beNULL
if the thread-safe function was created withoutjs_callback
.[in] context
: The optional data with which the thread-safe function was created.[in] data
: Data created by the secondary thread. It is the responsibility of the callback to convert this native data to JavaScript values (with N-API functions) that can be passed as parameters whenjs_callback
is invoked. This pointer is managed entirely by the threads and this callback. Thus this callback should free the data.
Unless for reasons discussed in Object Lifetime Management, creating a handle and/or callback scope inside the function body is not necessary.
napi_async_cleanup_hook#
Function pointer used with napi_add_async_cleanup_hook
. It will be called
when the environment is being torn down.
Callback functions must satisfy the following signature:
typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle,
void* data);
[in] handle
: The handle that must be passed tonapi_remove_async_cleanup_hook
after completion of the asynchronous cleanup.[in] data
: The data that was passed tonapi_add_async_cleanup_hook
.
The body of the function should initiate the asynchronous cleanup actions at the
end of which handle
must be passed in a call to
napi_remove_async_cleanup_hook
.
Error handling#
N-API uses both return values and JavaScript exceptions for error handling. The following sections explain the approach for each case.
Return values#
All of the N-API functions share the same error handling pattern. The
return type of all API functions is napi_status
.
The return value will be napi_ok
if the request was successful and
no uncaught JavaScript exception was thrown. If an error occurred AND
an exception was thrown, the napi_status
value for the error
will be returned. If an exception was thrown, and no error occurred,
napi_pending_exception
will be returned.
In cases where a return value other than napi_ok
or
napi_pending_exception
is returned, napi_is_exception_pending
must be called to check if an exception is pending.
See the section on exceptions for more details.
The full set of possible napi_status
values is defined
in napi_api_types.h
.
The napi_status
return value provides a VM-independent representation of
the error which occurred. In some cases it is useful to be able to get
more detailed information, including a string representing the error as well as
VM (engine)-specific information.
In order to retrieve this information napi_get_last_error_info
is provided which returns a napi_extended_error_info
structure.
The format of the napi_extended_error_info
structure is as follows:
typedef struct napi_extended_error_info {
const char* error_message;
void* engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
};
error_message
: Textual representation of the error that occurred.engine_reserved
: Opaque handle reserved for engine use only.engine_error_code
: VM specific error code.error_code
: n-api status code for the last error.
napi_get_last_error_info
returns the information for the last
N-API call that was made.
Do not rely on the content or format of any of the extended information as it is not subject to SemVer and may change at any time. It is intended only for logging purposes.
napi_get_last_error_info#
napi_status
napi_get_last_error_info(napi_env env,
const napi_extended_error_info** result);
[in] env
: The environment that the API is invoked under.[out] result
: Thenapi_extended_error_info
structure with more information about the error.
Returns napi_ok
if the API succeeded.
This API retrieves a napi_extended_error_info
structure with information
about the last error that occurred.
The content of the napi_extended_error_info
returned is only valid up until
an n-api function is called on the same env
.
Do not rely on the content or format of any of the extended information as it is not subject to SemVer and may change at any time. It is intended only for logging purposes.
This API can be called even if there is a pending JavaScript exception.
Exceptions#
Any N-API function call may result in a pending JavaScript exception. This is the case for any of the API functions, even those that may not cause the execution of JavaScript.
If the napi_status
returned by a function is napi_ok
then no
exception is pending and no additional action is required. If the
napi_status
returned is anything other than napi_ok
or
napi_pending_exception
, in order to try to recover and continue
instead of simply returning immediately, napi_is_exception_pending
must be called in order to determine if an exception is pending or not.
In many cases when an N-API function is called and an exception is
already pending, the function will return immediately with a
napi_status
of napi_pending_exception
. However, this is not the case
for all functions. N-API allows a subset of the functions to be
called to allow for some minimal cleanup before returning to JavaScript.
In that case, napi_status
will reflect the status for the function. It
will not reflect previous pending exceptions. To avoid confusion, check
the error status after every function call.
When an exception is pending one of two approaches can be employed.
The first approach is to do any appropriate cleanup and then return so that
execution will return to JavaScript. As part of the transition back to
JavaScript, the exception will be thrown at the point in the JavaScript
code where the native method was invoked. The behavior of most N-API calls
is unspecified while an exception is pending, and many will simply return
napi_pending_exception
, so do as little as possible and then return to
JavaScript where the exception can be handled.
The second approach is to try to handle the exception. There will be cases
where the native code can catch the exception, take the appropriate action,
and then continue. This is only recommended in specific cases
where it is known that the exception can be safely handled. In these
cases napi_get_and_clear_last_exception
can be used to get and
clear the exception. On success, result will contain the handle to
the last JavaScript Object
thrown. If it is determined, after
retrieving the exception, the exception cannot be handled after all
it can be re-thrown it with napi_throw
where error is the
JavaScript Error
object to be thrown.
The following utility functions are also available in case native code
needs to throw an exception or determine if a napi_value
is an instance
of a JavaScript Error
object: napi_throw_error
,
napi_throw_type_error
, napi_throw_range_error
and
napi_is_error
.
The following utility functions are also available in case native
code needs to create an Error
object: napi_create_error
,
napi_create_type_error
, and napi_create_range_error
,
where result is the napi_value
that refers to the newly created
JavaScript Error
object.
The Node.js project is adding error codes to all of the errors
generated internally. The goal is for applications to use these
error codes for all error checking. The associated error messages
will remain, but will only be meant to be used for logging and
display with the expectation that the message can change without
SemVer applying. In order to support this model with N-API, both
in internal functionality and for module specific functionality
(as its good practice), the throw_
and create_
functions
take an optional code parameter which is the string for the code
to be added to the error object. If the optional parameter is NULL
then no code will be associated with the error. If a code is provided,
the name associated with the error is also updated to be:
originalName [code]
where originalName
is the original name associated with the error
and code
is the code that was provided. For example, if the code
is 'ERR_ERROR_1'
and a TypeError
is being created the name will be:
TypeError [ERR_ERROR_1]
napi_throw#
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
[in] env
: The environment that the API is invoked under.[in] error
: The JavaScript value to be thrown.
Returns napi_ok
if the API succeeded.
This API throws the JavaScript value provided.
napi_throw_error#
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
const char* code,
const char* msg);
[in] env
: The environment that the API is invoked under.[in] code
: Optional error code to be set on the error.[in] msg
: C string representing the text to be associated with the error.
Returns napi_ok
if the API succeeded.
This API throws a JavaScript Error
with the text provided.
napi_throw_type_error#
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
const char* code,
const char* msg);
[in] env
: The environment that the API is invoked under.[in] code
: Optional error code to be set on the error.[in] msg
: C string representing the text to be associated with the error.
Returns napi_ok
if the API succeeded.
This API throws a JavaScript TypeError
with the text provided.
napi_throw_range_error#
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
const char* code,
const char* msg);
[in] env
: The environment that the API is invoked under.[in] code
: Optional error code to be set on the error.[in] msg
: C string representing the text to be associated with the error.
Returns napi_ok
if the API succeeded.
This API throws a JavaScript RangeError
with the text provided.
napi_is_error#
NAPI_EXTERN napi_status napi_is_error(napi_env env,
napi_value value,
bool* result);
[in] env
: The environment that the API is invoked under.[in] value
: Thenapi_value
to be checked.[out] result
: Boolean value that is set to true ifnapi_value
represents an error, false otherwise.
Returns napi_ok
if the API succeeded.
This API queries a napi_value
to check if it represents an error object.
napi_create_error#
NAPI_EXTERN napi_status napi_create_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] code
: Optionalnapi_value
with the string for the error code to be associated with the error.[in] msg
:napi_value
that references a JavaScriptString
to be used as the message for theError
.[out] result
:napi_value
representing the error created.
Returns napi_ok
if the API succeeded.
This API returns a JavaScript Error
with the text provided.
napi_create_type_error#
NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] code
: Optionalnapi_value
with the string for the error code to be associated with the error.[in] msg
:napi_value
that references a JavaScriptString
to be used as the message for theError
.[out] result
:napi_value
representing the error created.
Returns napi_ok
if the API succeeded.
This API returns a JavaScript TypeError
with the text provided.
napi_create_range_error#
NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] code
: Optionalnapi_value
with the string for the error code to be associated with the error.[in] msg
:napi_value
that references a JavaScriptString
to be used as the message for theError
.[out] result
:napi_value
representing the error created.
Returns napi_ok
if the API succeeded.
This API returns a JavaScript RangeError
with the text provided.
napi_get_and_clear_last_exception#
napi_status napi_get_and_clear_last_exception(napi_env env,
napi_value* result);
[in] env
: The environment that the API is invoked under.[out] result
: The exception if one is pending,NULL
otherwise.
Returns napi_ok
if the API succeeded.
This API can be called even if there is a pending JavaScript exception.
napi_is_exception_pending#
napi_status napi_is_exception_pending(napi_env env, bool* result);
[in] env
: The environment that the API is invoked under.[out] result
: Boolean value that is set to true if an exception is pending.
Returns napi_ok
if the API succeeded.
This API can be called even if there is a pending JavaScript exception.
napi_fatal_exception#
napi_status napi_fatal_exception(napi_env env, napi_value err);
[in] env
: The environment that the API is invoked under.[in] err
: The error that is passed to'uncaughtException'
.
Trigger an 'uncaughtException'
in JavaScript. Useful if an async
callback throws an exception with no way to recover.
Fatal errors#
In the event of an unrecoverable error in a native module, a fatal error can be thrown to immediately terminate the process.
napi_fatal_error#
NAPI_NO_RETURN void napi_fatal_error(const char* location,
size_t location_len,
const char* message,
size_t message_len);
[in] location
: Optional location at which the error occurred.[in] location_len
: The length of the location in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.[in] message
: The message associated with the error.[in] message_len
: The length of the message in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.
The function call does not return, the process will be terminated.
This API can be called even if there is a pending JavaScript exception.
Object lifetime management#
As N-API calls are made, handles to objects in the heap for the underlying
VM may be returned as napi_values
. These handles must hold the
objects 'live' until they are no longer required by the native code,
otherwise the objects could be collected before the native code was
finished using them.
As object handles are returned they are associated with a 'scope'. The lifespan for the default scope is tied to the lifespan of the native method call. The result is that, by default, handles remain valid and the objects associated with these handles will be held live for the lifespan of the native method call.
In many cases, however, it is necessary that the handles remain valid for either a shorter or longer lifespan than that of the native method. The sections which follow describe the N-API functions that can be used to change the handle lifespan from the default.
Making handle lifespan shorter than that of the native method#
It is often necessary to make the lifespan of handles shorter than the lifespan of a native method. For example, consider a native method that has a loop which iterates through the elements in a large array:
for (int i = 0; i < 1000000; i++) {
napi_value result;
napi_status status = napi_get_element(env, object, i, &result);
if (status != napi_ok) {
break;
}
// do something with element
}
This would result in a large number of handles being created, consuming substantial resources. In addition, even though the native code could only use the most recent handle, all of the associated objects would also be kept alive since they all share the same scope.
To handle this case, N-API provides the ability to establish a new 'scope' to
which newly created handles will be associated. Once those handles
are no longer required, the scope can be 'closed' and any handles associated
with the scope are invalidated. The methods available to open/close scopes are
napi_open_handle_scope
and napi_close_handle_scope
.
N-API only supports a single nested hierarchy of scopes. There is only one active scope at any time, and all new handles will be associated with that scope while it is active. Scopes must be closed in the reverse order from which they are opened. In addition, all scopes created within a native method must be closed before returning from that method.
Taking the earlier example, adding calls to napi_open_handle_scope
and
napi_close_handle_scope
would ensure that at most a single handle
is valid throughout the execution of the loop:
for (int i = 0; i < 1000000; i++) {
napi_handle_scope scope;
napi_status status = napi_open_handle_scope(env, &scope);
if (status != napi_ok) {
break;
}
napi_value result;
status = napi_get_element(env, object, i, &result);
if (status != napi_ok) {
break;
}
// do something with element
status = napi_close_handle_scope(env, scope);
if (status != napi_ok) {
break;
}
}
When nesting scopes, there are cases where a handle from an inner scope needs to live beyond the lifespan of that scope. N-API supports an 'escapable scope' in order to support this case. An escapable scope allows one handle to be 'promoted' so that it 'escapes' the current scope and the lifespan of the handle changes from the current scope to that of the outer scope.
The methods available to open/close escapable scopes are
napi_open_escapable_handle_scope
and
napi_close_escapable_handle_scope
.
The request to promote a handle is made through napi_escape_handle
which
can only be called once.
napi_open_handle_scope#
NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env,
napi_handle_scope* result);
[in] env
: The environment that the API is invoked under.[out] result
:napi_value
representing the new scope.
Returns napi_ok
if the API succeeded.
This API opens a new scope.
napi_close_handle_scope#
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
napi_handle_scope scope);
[in] env
: The environment that the API is invoked under.[in] scope
:napi_value
representing the scope to be closed.
Returns napi_ok
if the API succeeded.
This API closes the scope passed in. Scopes must be closed in the reverse order from which they were created.
This API can be called even if there is a pending JavaScript exception.
napi_open_escapable_handle_scope#
NAPI_EXTERN napi_status
napi_open_escapable_handle_scope(napi_env env,
napi_handle_scope* result);
[in] env
: The environment that the API is invoked under.[out] result
:napi_value
representing the new scope.
Returns napi_ok
if the API succeeded.
This API opens a new scope from which one object can be promoted to the outer scope.
napi_close_escapable_handle_scope#
NAPI_EXTERN napi_status
napi_close_escapable_handle_scope(napi_env env,
napi_handle_scope scope);
[in] env
: The environment that the API is invoked under.[in] scope
:napi_value
representing the scope to be closed.
Returns napi_ok
if the API succeeded.
This API closes the scope passed in. Scopes must be closed in the reverse order from which they were created.
This API can be called even if there is a pending JavaScript exception.
napi_escape_handle#
napi_status napi_escape_handle(napi_env env,
napi_escapable_handle_scope scope,
napi_value escapee,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] scope
:napi_value
representing the current scope.[in] escapee
:napi_value
representing the JavaScriptObject
to be escaped.[out] result
:napi_value
representing the handle to the escapedObject
in the outer scope.
Returns napi_ok
if the API succeeded.
This API promotes the handle to the JavaScript object so that it is valid for the lifetime of the outer scope. It can only be called once per scope. If it is called more than once an error will be returned.
This API can be called even if there is a pending JavaScript exception.
References to objects with a lifespan longer than that of the native method#
In some cases an addon will need to be able to create and reference objects
with a lifespan longer than that of a single native method invocation. For
example, to create a constructor and later use that constructor
in a request to creates instances, it must be possible to reference
the constructor object across many different instance creation requests. This
would not be possible with a normal handle returned as a napi_value
as
described in the earlier section. The lifespan of a normal handle is
managed by scopes and all scopes must be closed before the end of a native
method.
N-API provides methods to create persistent references to an object. Each persistent reference has an associated count with a value of 0 or higher. The count determines if the reference will keep the corresponding object live. References with a count of 0 do not prevent the object from being collected and are often called 'weak' references. Any count greater than 0 will prevent the object from being collected.
References can be created with an initial reference count. The count can
then be modified through napi_reference_ref
and
napi_reference_unref
. If an object is collected while the count
for a reference is 0, all subsequent calls to
get the object associated with the reference napi_get_reference_value
will return NULL
for the returned napi_value
. An attempt to call
napi_reference_ref
for a reference whose object has been collected
will result in an error.
References must be deleted once they are no longer required by the addon. When a reference is deleted it will no longer prevent the corresponding object from being collected. Failure to delete a persistent reference will result in a 'memory leak' with both the native memory for the persistent reference and the corresponding object on the heap being retained forever.
There can be multiple persistent references created which refer to the same object, each of which will either keep the object live or not based on its individual count.
napi_create_reference#
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
napi_value value,
uint32_t initial_refcount,
napi_ref* result);
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing theObject
to which we want a reference.[in] initial_refcount
: Initial reference count for the new reference.[out] result
:napi_ref
pointing to the new reference.
Returns napi_ok
if the API succeeded.
This API create a new reference with the specified reference count
to the Object
passed in.
napi_delete_reference#
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
[in] env
: The environment that the API is invoked under.[in] ref
:napi_ref
to be deleted.
Returns napi_ok
if the API succeeded.
This API deletes the reference passed in.
This API can be called even if there is a pending JavaScript exception.
napi_reference_ref#
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
napi_ref ref,
uint32_t* result);
[in] env
: The environment that the API is invoked under.[in] ref
:napi_ref
for which the reference count will be incremented.[out] result
: The new reference count.
Returns napi_ok
if the API succeeded.
This API increments the reference count for the reference passed in and returns the resulting reference count.
napi_reference_unref#
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
napi_ref ref,
uint32_t* result);
[in] env
: The environment that the API is invoked under.[in] ref
:napi_ref
for which the reference count will be decremented.[out] result
: The new reference count.
Returns napi_ok
if the API succeeded.
This API decrements the reference count for the reference passed in and returns the resulting reference count.
napi_get_reference_value#
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
napi_ref ref,
napi_value* result);
the napi_value passed
in or out of these methods is a handle to the
object to which the reference is related.
[in] env
: The environment that the API is invoked under.[in] ref
:napi_ref
for which we requesting the correspondingObject
.[out] result
: Thenapi_value
for theObject
referenced by thenapi_ref
.
Returns napi_ok
if the API succeeded.
If still valid, this API returns the napi_value
representing the
JavaScript Object
associated with the napi_ref
. Otherwise, result
will be NULL
.
Cleanup on exit of the current Node.js instance#
While a Node.js process typically releases all its resources when exiting, embedders of Node.js, or future Worker support, may require addons to register clean-up hooks that will be run once the current Node.js instance exits.
N-API provides functions for registering and un-registering such callbacks. When those callbacks are run, all resources that are being held by the addon should be freed up.
napi_add_env_cleanup_hook#
NODE_EXTERN napi_status napi_add_env_cleanup_hook(napi_env env,
void (*fun)(void* arg),
void* arg);
Registers fun
as a function to be run with the arg
parameter once the
current Node.js environment exits.
A function can safely be specified multiple times with different
arg
values. In that case, it will be called multiple times as well.
Providing the same fun
and arg
values multiple times is not allowed
and will lead the process to abort.
The hooks will be called in reverse order, i.e. the most recently added one will be called first.
Removing this hook can be done by using napi_remove_env_cleanup_hook
.
Typically, that happens when the resource for which this hook was added
is being torn down anyway.
For asynchronous cleanup, napi_add_async_cleanup_hook
is available.
napi_remove_env_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env,
void (*fun)(void* arg),
void* arg);
Unregisters fun
as a function to be run with the arg
parameter once the
current Node.js environment exits. Both the argument and the function value
need to be exact matches.
The function must have originally been registered
with napi_add_env_cleanup_hook
, otherwise the process will abort.
napi_add_async_cleanup_hook#
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
napi_env env,
napi_async_cleanup_hook hook,
void* arg,
napi_async_cleanup_hook_handle* remove_handle);
[in] env
: The environment that the API is invoked under.[in] hook
: The function pointer to call at environment teardown.[in] arg
: The pointer to pass tohook
when it gets called.[out] remove_handle
: Optional handle that refers to the asynchronous cleanup hook.
Registers hook
, which is a function of type napi_async_cleanup_hook
, as
a function to be run with the remove_handle
and arg
parameters once the
current Node.js environment exits.
Unlike napi_add_env_cleanup_hook
, the hook is allowed to be asynchronous.
Otherwise, behavior generally matches that of napi_add_env_cleanup_hook
.
If remove_handle
is not NULL
, an opaque value will be stored in it
that must later be passed to napi_remove_async_cleanup_hook
,
regardless of whether the hook has already been invoked.
Typically, that happens when the resource for which this hook was added
is being torn down anyway.
napi_remove_async_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
napi_async_cleanup_hook_handle remove_handle);
[in] remove_handle
: The handle to an asynchronous cleanup hook that was created withnapi_add_async_cleanup_hook
.
Unregisters the cleanup hook corresponding to remove_handle
. This will prevent
the hook from being executed, unless it has already started executing.
This must be called on any napi_async_cleanup_hook_handle
value obtained
from napi_add_async_cleanup_hook
.
Module registration#
N-API modules are registered in a manner similar to other modules
except that instead of using the NODE_MODULE
macro the following
is used:
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
The next difference is the signature for the Init
method. For a N-API
module it is as follows:
napi_value Init(napi_env env, napi_value exports);
The return value from Init
is treated as the exports
object for the module.
The Init
method is passed an empty object via the exports
parameter as a
convenience. If Init
returns NULL
, the parameter passed as exports
is
exported by the module. N-API modules cannot modify the module
object but can
specify anything as the exports
property of the module.
To add the method hello
as a function so that it can be called as a method
provided by the addon:
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor desc = {
"hello",
NULL,
Method,
NULL,
NULL,
NULL,
napi_writable | napi_enumerable | napi_configurable,
NULL
};
status = napi_define_properties(env, exports, 1, &desc);
if (status != napi_ok) return NULL;
return exports;
}
To set a function to be returned by the require()
for the addon:
napi_value Init(napi_env env, napi_value exports) {
napi_value method;
napi_status status;
status = napi_create_function(env, "exports", NAPI_AUTO_LENGTH, Method, NULL, &method);
if (status != napi_ok) return NULL;
return method;
}
To define a class so that new instances can be created (often used with Object wrap):
// NOTE: partial example, not all referenced code is included
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor properties[] = {
{ "value", NULL, NULL, GetValue, SetValue, NULL, napi_writable | napi_configurable, NULL },
DECLARE_NAPI_METHOD("plusOne", PlusOne),
DECLARE_NAPI_METHOD("multiply", Multiply),
};
napi_value cons;
status =
napi_define_class(env, "MyObject", New, NULL, 3, properties, &cons);
if (status != napi_ok) return NULL;
status = napi_create_reference(env, cons, 1, &constructor);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "MyObject", cons);
if (status != napi_ok) return NULL;
return exports;
}
If the module will be loaded multiple times during the lifetime of the Node.js
process, use the NAPI_MODULE_INIT
macro to initialize the module:
NAPI_MODULE_INIT() {
napi_value answer;
napi_status result;
status = napi_create_int64(env, 42, &answer);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "answer", answer);
if (status != napi_ok) return NULL;
return exports;
}
This macro includes NAPI_MODULE
, and declares an Init
function with a
special name and with visibility beyond the addon. This will allow Node.js to
initialize the module even if it is loaded multiple times.
There are a few design considerations when declaring a module that may be loaded multiple times. The documentation of context-aware addons provides more details.
The variables env
and exports
will be available inside the function body
following the macro invocation.
For more details on setting properties on objects, see the section on Working with JavaScript properties.
For more details on building addon modules in general, refer to the existing API.
Working with JavaScript values#
N-API exposes a set of APIs to create all types of JavaScript values. Some of these types are documented under Section 6 of the ECMAScript Language Specification.
Fundamentally, these APIs are used to do one of the following:
- Create a new JavaScript object
- Convert from a primitive C type to an N-API value
- Convert from N-API value to a primitive C type
- Get global instances including
undefined
andnull
N-API values are represented by the type napi_value
.
Any N-API call that requires a JavaScript value takes in a napi_value
.
In some cases, the API does check the type of the napi_value
up-front.
However, for better performance, it's better for the caller to make sure that
the napi_value
in question is of the JavaScript type expected by the API.
Enum types#
napi_key_collection_mode#
typedef enum {
napi_key_include_prototypes,
napi_key_own_only
} napi_key_collection_mode;
Describes the Keys/Properties
filter enums:
napi_key_collection_mode
limits the range of collected properties.
napi_key_own_only
limits the collected properties to the given
object only. napi_key_include_prototypes
will include all keys
of the objects's prototype chain as well.
napi_key_filter#
typedef enum {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
} napi_key_filter;
Property filter bits. They can be or'ed to build a composite filter.
napi_key_conversion#
typedef enum {
napi_key_keep_numbers,
napi_key_numbers_to_strings
} napi_key_conversion;
napi_key_numbers_to_strings
will convert integer indices to
strings. napi_key_keep_numbers
will return numbers for integer
indices.
napi_valuetype#
typedef enum {
// ES6 types (corresponds to typeof)
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint,
} napi_valuetype;
Describes the type of a napi_value
. This generally corresponds to the types
described in Section 6.1 of the ECMAScript Language Specification.
In addition to types in that section, napi_valuetype
can also represent
Function
s and Object
s with external data.
A JavaScript value of type napi_external
appears in JavaScript as a plain
object such that no properties can be set on it, and no prototype.
napi_typedarray_type#
typedef enum {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
} napi_typedarray_type;
This represents the underlying binary scalar datatype of the TypedArray
.
Elements of this enum correspond to
Section 22.2 of the ECMAScript Language Specification.
Object creation functions#
napi_create_array#
napi_status napi_create_array(napi_env env, napi_value* result)
[in] env
: The environment that the N-API call is invoked under.[out] result
: Anapi_value
representing a JavaScriptArray
.
Returns napi_ok
if the API succeeded.
This API returns an N-API value corresponding to a JavaScript Array
type.
JavaScript arrays are described in
Section 22.1 of the ECMAScript Language Specification.
napi_create_array_with_length#
napi_status napi_create_array_with_length(napi_env env,
size_t length,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] length
: The initial length of theArray
.[out] result
: Anapi_value
representing a JavaScriptArray
.
Returns napi_ok
if the API succeeded.
This API returns an N-API value corresponding to a JavaScript Array
type.
The Array
's length property is set to the passed-in length parameter.
However, the underlying buffer is not guaranteed to be pre-allocated by the VM
when the array is created. That behavior is left to the underlying VM
implementation. If the buffer must be a contiguous block of memory that can be
directly read and/or written via C, consider using
napi_create_external_arraybuffer
.
JavaScript arrays are described in Section 22.1 of the ECMAScript Language Specification.
napi_create_arraybuffer#
napi_status napi_create_arraybuffer(napi_env env,
size_t byte_length,
void** data,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] length
: The length in bytes of the array buffer to create.[out] data
: Pointer to the underlying byte buffer of theArrayBuffer
.[out] result
: Anapi_value
representing a JavaScriptArrayBuffer
.
Returns napi_ok
if the API succeeded.
This API returns an N-API value corresponding to a JavaScript ArrayBuffer
.
ArrayBuffer
s are used to represent fixed-length binary data buffers. They are
normally used as a backing-buffer for TypedArray
objects.
The ArrayBuffer
allocated will have an underlying byte buffer whose size is
determined by the length
parameter that's passed in.
The underlying buffer is optionally returned back to the caller in case the
caller wants to directly manipulate the buffer. This buffer can only be
written to directly from native code. To write to this buffer from JavaScript,
a typed array or DataView
object would need to be created.
JavaScript ArrayBuffer
objects are described in
Section 24.1 of the ECMAScript Language Specification.
napi_create_buffer#
napi_status napi_create_buffer(napi_env env,
size_t size,
void** data,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] size
: Size in bytes of the underlying buffer.[out] data
: Raw pointer to the underlying buffer.[out] result
: Anapi_value
representing anode::Buffer
.
Returns napi_ok
if the API succeeded.
This API allocates a node::Buffer
object. While this is still a
fully-supported data structure, in most cases using a TypedArray
will suffice.
napi_create_buffer_copy#
napi_status napi_create_buffer_copy(napi_env env,
size_t length,
const void* data,
void** result_data,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] size
: Size in bytes of the input buffer (should be the same as the size of the new buffer).[in] data
: Raw pointer to the underlying buffer to copy from.[out] result_data
: Pointer to the newBuffer
's underlying data buffer.[out] result
: Anapi_value
representing anode::Buffer
.
Returns napi_ok
if the API succeeded.
This API allocates a node::Buffer
object and initializes it with data copied
from the passed-in buffer. While this is still a fully-supported data
structure, in most cases using a TypedArray
will suffice.
napi_create_date#
napi_status napi_create_date(napi_env env,
double time,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] time
: ECMAScript time value in milliseconds since 01 January, 1970 UTC.[out] result
: Anapi_value
representing a JavaScriptDate
.
Returns napi_ok
if the API succeeded.
This API does not observe leap seconds; they are ignored, as ECMAScript aligns with POSIX time specification.
This API allocates a JavaScript Date
object.
JavaScript Date
objects are described in
Section 20.3 of the ECMAScript Language Specification.
napi_create_external#
napi_status napi_create_external(napi_env env,
void* data,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] data
: Raw pointer to the external data.[in] finalize_cb
: Optional callback to call when the external value is being collected.napi_finalize
provides more details.[in] finalize_hint
: Optional hint to pass to the finalize callback during collection.[out] result
: Anapi_value
representing an external value.
Returns napi_ok
if the API succeeded.
This API allocates a JavaScript value with external data attached to it. This
is used to pass external data through JavaScript code, so it can be retrieved
later by native code using napi_get_value_external
.
The API adds a napi_finalize
callback which will be called when the JavaScript
object just created is ready for garbage collection. It is similar to
napi_wrap()
except that:
- the native data cannot be retrieved later using
napi_unwrap()
, - nor can it be removed later using
napi_remove_wrap()
, and - the object created by the API can be used with
napi_wrap()
.
The created value is not an object, and therefore does not support additional
properties. It is considered a distinct value type: calling napi_typeof()
with
an external value yields napi_external
.
napi_create_external_arraybuffer#
napi_status
napi_create_external_arraybuffer(napi_env env,
void* external_data,
size_t byte_length,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] external_data
: Pointer to the underlying byte buffer of theArrayBuffer
.[in] byte_length
: The length in bytes of the underlying buffer.[in] finalize_cb
: Optional callback to call when theArrayBuffer
is being collected.napi_finalize
provides more details.[in] finalize_hint
: Optional hint to pass to the finalize callback during collection.[out] result
: Anapi_value
representing a JavaScriptArrayBuffer
.
Returns napi_ok
if the API succeeded.
This API returns an N-API value corresponding to a JavaScript ArrayBuffer
.
The underlying byte buffer of the ArrayBuffer
is externally allocated and
managed. The caller must ensure that the byte buffer remains valid until the
finalize callback is called.
The API adds a napi_finalize
callback which will be called when the JavaScript
object just created is ready for garbage collection. It is similar to
napi_wrap()
except that:
- the native data cannot be retrieved later using
napi_unwrap()
, - nor can it be removed later using
napi_remove_wrap()
, and - the object created by the API can be used with
napi_wrap()
.
JavaScript ArrayBuffer
s are described in
Section 24.1 of the ECMAScript Language Specification.
napi_create_external_buffer#
napi_status napi_create_external_buffer(napi_env env,
size_t length,
void* data,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] length
: Size in bytes of the input buffer (should be the same as the size of the new buffer).[in] data
: Raw pointer to the underlying buffer to expose to JavaScript.[in] finalize_cb
: Optional callback to call when theArrayBuffer
is being collected.napi_finalize
provides more details.[in] finalize_hint
: Optional hint to pass to the finalize callback during collection.[out] result
: Anapi_value
representing anode::Buffer
.
Returns napi_ok
if the API succeeded.
This API allocates a node::Buffer
object and initializes it with data
backed by the passed in buffer. While this is still a fully-supported data
structure, in most cases using a TypedArray
will suffice.
The API adds a napi_finalize
callback which will be called when the JavaScript
object just created is ready for garbage collection. It is similar to
napi_wrap()
except that:
- the native data cannot be retrieved later using
napi_unwrap()
, - nor can it be removed later using
napi_remove_wrap()
, and - the object created by the API can be used with
napi_wrap()
.
For Node.js >=4 Buffers
are Uint8Array
s.
napi_create_object#
napi_status napi_create_object(napi_env env, napi_value* result)
[in] env
: The environment that the API is invoked under.[out] result
: Anapi_value
representing a JavaScriptObject
.
Returns napi_ok
if the API succeeded.
This API allocates a default JavaScript Object
.
It is the equivalent of doing new Object()
in JavaScript.
The JavaScript Object
type is described in Section 6.1.7 of the
ECMAScript Language Specification.
napi_create_symbol#
napi_status napi_create_symbol(napi_env env,
napi_value description,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] description
: Optionalnapi_value
which refers to a JavaScriptString
to be set as the description for the symbol.[out] result
: Anapi_value
representing a JavaScriptSymbol
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript Symbol
object from a UTF8-encoded C string.
The JavaScript Symbol
type is described in Section 19.4
of the ECMAScript Language Specification.
napi_create_typedarray#
napi_status napi_create_typedarray(napi_env env,
napi_typedarray_type type,
size_t length,
napi_value arraybuffer,
size_t byte_offset,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] type
: Scalar datatype of the elements within theTypedArray
.[in] length
: Number of elements in theTypedArray
.[in] arraybuffer
:ArrayBuffer
underlying the typed array.[in] byte_offset
: The byte offset within theArrayBuffer
from which to start projecting theTypedArray
.[out] result
: Anapi_value
representing a JavaScriptTypedArray
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript TypedArray
object over an existing
ArrayBuffer
. TypedArray
objects provide an array-like view over an
underlying data buffer where each element has the same underlying binary scalar
datatype.
It's required that (length * size_of_element) + byte_offset
should
be <= the size in bytes of the array passed in. If not, a RangeError
exception
is raised.
JavaScript TypedArray
objects are described in
Section 22.2 of the ECMAScript Language Specification.
napi_create_dataview#
napi_status napi_create_dataview(napi_env env,
size_t byte_length,
napi_value arraybuffer,
size_t byte_offset,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] length
: Number of elements in theDataView
.[in] arraybuffer
:ArrayBuffer
underlying theDataView
.[in] byte_offset
: The byte offset within theArrayBuffer
from which to start projecting theDataView
.[out] result
: Anapi_value
representing a JavaScriptDataView
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript DataView
object over an existing ArrayBuffer
.
DataView
objects provide an array-like view over an underlying data buffer,
but one which allows items of different size and type in the ArrayBuffer
.
It is required that byte_length + byte_offset
is less than or equal to the
size in bytes of the array passed in. If not, a RangeError
exception is
raised.
JavaScript DataView
objects are described in
Section 24.3 of the ECMAScript Language Specification.
Functions to convert from C types to N-API#
napi_create_int32#
napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: Integer value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptNumber
.
Returns napi_ok
if the API succeeded.
This API is used to convert from the C int32_t
type to the JavaScript
Number
type.
The JavaScript Number
type is described in
Section 6.1.6 of the ECMAScript Language Specification.
napi_create_uint32#
napi_status napi_create_uint32(napi_env env, uint32_t value, napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: Unsigned integer value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptNumber
.
Returns napi_ok
if the API succeeded.
This API is used to convert from the C uint32_t
type to the JavaScript
Number
type.
The JavaScript Number
type is described in
Section 6.1.6 of the ECMAScript Language Specification.
napi_create_int64#
napi_status napi_create_int64(napi_env env, int64_t value, napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: Integer value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptNumber
.
Returns napi_ok
if the API succeeded.
This API is used to convert from the C int64_t
type to the JavaScript
Number
type.
The JavaScript Number
type is described in Section 6.1.6
of the ECMAScript Language Specification. Note the complete range of int64_t
cannot be represented with full precision in JavaScript. Integer values
outside the range of Number.MIN_SAFE_INTEGER
-(2**53 - 1)
-
Number.MAX_SAFE_INTEGER
(2**53 - 1)
will lose precision.
napi_create_double#
napi_status napi_create_double(napi_env env, double value, napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: Double-precision value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptNumber
.
Returns napi_ok
if the API succeeded.
This API is used to convert from the C double
type to the JavaScript
Number
type.
The JavaScript Number
type is described in
Section 6.1.6 of the ECMAScript Language Specification.
napi_create_bigint_int64#
napi_status napi_create_bigint_int64(napi_env env,
int64_t value,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] value
: Integer value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptBigInt
.
Returns napi_ok
if the API succeeded.
This API converts the C int64_t
type to the JavaScript BigInt
type.
napi_create_bigint_uint64#
napi_status napi_create_bigint_uint64(napi_env env,
uint64_t value,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] value
: Unsigned integer value to be represented in JavaScript.[out] result
: Anapi_value
representing a JavaScriptBigInt
.
Returns napi_ok
if the API succeeded.
This API converts the C uint64_t
type to the JavaScript BigInt
type.
napi_create_bigint_words#
napi_status napi_create_bigint_words(napi_env env,
int sign_bit,
size_t word_count,
const uint64_t* words,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] sign_bit
: Determines if the resultingBigInt
will be positive or negative.[in] word_count
: The length of thewords
array.[in] words
: An array ofuint64_t
little-endian 64-bit words.[out] result
: Anapi_value
representing a JavaScriptBigInt
.
Returns napi_ok
if the API succeeded.
This API converts an array of unsigned 64-bit words into a single BigInt
value.
The resulting BigInt
is calculated as: (–1)sign_bit
(words[0]
× (264)0 + words[1]
× (264)1 + …)
napi_create_string_latin1#
napi_status napi_create_string_latin1(napi_env env,
const char* str,
size_t length,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] str
: Character buffer representing an ISO-8859-1-encoded string.[in] length
: The length of the string in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.[out] result
: Anapi_value
representing a JavaScriptString
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript String
object from an ISO-8859-1-encoded C
string. The native string is copied.
The JavaScript String
type is described in
Section 6.1.4 of the ECMAScript Language Specification.
napi_create_string_utf16#
napi_status napi_create_string_utf16(napi_env env,
const char16_t* str,
size_t length,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] str
: Character buffer representing a UTF16-LE-encoded string.[in] length
: The length of the string in two-byte code units, orNAPI_AUTO_LENGTH
if it is null-terminated.[out] result
: Anapi_value
representing a JavaScriptString
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript String
object from a UTF16-LE-encoded C string.
The native string is copied.
The JavaScript String
type is described in
Section 6.1.4 of the ECMAScript Language Specification.
napi_create_string_utf8#
napi_status napi_create_string_utf8(napi_env env,
const char* str,
size_t length,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] str
: Character buffer representing a UTF8-encoded string.[in] length
: The length of the string in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.[out] result
: Anapi_value
representing a JavaScriptString
.
Returns napi_ok
if the API succeeded.
This API creates a JavaScript String
object from a UTF8-encoded C string.
The native string is copied.
The JavaScript String
type is described in
Section 6.1.4 of the ECMAScript Language Specification.
Functions to convert from N-API to C types#
napi_get_array_length#
napi_status napi_get_array_length(napi_env env,
napi_value value,
uint32_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing the JavaScriptArray
whose length is being queried.[out] result
:uint32
representing length of the array.
Returns napi_ok
if the API succeeded.
This API returns the length of an array.
Array
length is described in Section 22.1.4.1 of the ECMAScript Language
Specification.
napi_get_arraybuffer_info#
napi_status napi_get_arraybuffer_info(napi_env env,
napi_value arraybuffer,
void** data,
size_t* byte_length)
[in] env
: The environment that the API is invoked under.[in] arraybuffer
:napi_value
representing theArrayBuffer
being queried.[out] data
: The underlying data buffer of theArrayBuffer
. If byte_length is0
, this may beNULL
or any other pointer value.[out] byte_length
: Length in bytes of the underlying data buffer.
Returns napi_ok
if the API succeeded.
This API is used to retrieve the underlying data buffer of an ArrayBuffer
and
its length.
WARNING: Use caution while using this API. The lifetime of the underlying data
buffer is managed by the ArrayBuffer
even after it's returned. A
possible safe way to use this API is in conjunction with
napi_create_reference
, which can be used to guarantee control over the
lifetime of the ArrayBuffer
. It's also safe to use the returned data buffer
within the same callback as long as there are no calls to other APIs that might
trigger a GC.
napi_get_buffer_info#
napi_status napi_get_buffer_info(napi_env env,
napi_value value,
void** data,
size_t* length)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing thenode::Buffer
being queried.[out] data
: The underlying data buffer of thenode::Buffer
. If length is0
, this may beNULL
or any other pointer value.[out] length
: Length in bytes of the underlying data buffer.
Returns napi_ok
if the API succeeded.
This API is used to retrieve the underlying data buffer of a node::Buffer
and it's length.
Warning: Use caution while using this API since the underlying data buffer's lifetime is not guaranteed if it's managed by the VM.
napi_get_prototype#
napi_status napi_get_prototype(napi_env env,
napi_value object,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] object
:napi_value
representing JavaScriptObject
whose prototype to return. This returns the equivalent ofObject.getPrototypeOf
(which is not the same as the function'sprototype
property).[out] result
:napi_value
representing prototype of the given object.
Returns napi_ok
if the API succeeded.
napi_get_typedarray_info#
napi_status napi_get_typedarray_info(napi_env env,
napi_value typedarray,
napi_typedarray_type* type,
size_t* length,
void** data,
napi_value* arraybuffer,
size_t* byte_offset)
[in] env
: The environment that the API is invoked under.[in] typedarray
:napi_value
representing theTypedArray
whose properties to query.[out] type
: Scalar datatype of the elements within theTypedArray
.[out] length
: The number of elements in theTypedArray
.[out] data
: The data buffer underlying theTypedArray
adjusted by thebyte_offset
value so that it points to the first element in theTypedArray
. If the length of the array is0
, this may beNULL
or any other pointer value.[out] arraybuffer
: TheArrayBuffer
underlying theTypedArray
.[out] byte_offset
: The byte offset within the underlying native array at which the first element of the arrays is located. The value for the data parameter has already been adjusted so that data points to the first element in the array. Therefore, the first byte of the native array would be atdata - byte_offset
.
Returns napi_ok
if the API succeeded.
This API returns various properties of a typed array.
Warning: Use caution while using this API since the underlying data buffer is managed by the VM.
napi_get_dataview_info#
napi_status napi_get_dataview_info(napi_env env,
napi_value dataview,
size_t* byte_length,
void** data,
napi_value* arraybuffer,
size_t* byte_offset)
[in] env
: The environment that the API is invoked under.[in] dataview
:napi_value
representing theDataView
whose properties to query.[out] byte_length
:Number
of bytes in theDataView
.[out] data
: The data buffer underlying theDataView
. If byte_length is0
, this may beNULL
or any other pointer value.[out] arraybuffer
:ArrayBuffer
underlying theDataView
.[out] byte_offset
: The byte offset within the data buffer from which to start projecting theDataView
.
Returns napi_ok
if the API succeeded.
This API returns various properties of a DataView
.
napi_get_date_value#
napi_status napi_get_date_value(napi_env env,
napi_value value,
double* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing a JavaScriptDate
.[out] result
: Time value as adouble
represented as milliseconds since midnight at the beginning of 01 January, 1970 UTC.
This API does not observe leap seconds; they are ignored, as ECMAScript aligns with POSIX time specification.
Returns napi_ok
if the API succeeded. If a non-date napi_value
is passed
in it returns napi_date_expected
.
This API returns the C double primitive of time value for the given JavaScript
Date
.
napi_get_value_bool#
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptBoolean
.[out] result
: C boolean primitive equivalent of the given JavaScriptBoolean
.
Returns napi_ok
if the API succeeded. If a non-boolean napi_value
is
passed in it returns napi_boolean_expected
.
This API returns the C boolean primitive equivalent of the given JavaScript
Boolean
.
napi_get_value_double#
napi_status napi_get_value_double(napi_env env,
napi_value value,
double* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptNumber
.[out] result
: C double primitive equivalent of the given JavaScriptNumber
.
Returns napi_ok
if the API succeeded. If a non-number napi_value
is passed
in it returns napi_number_expected
.
This API returns the C double primitive equivalent of the given JavaScript
Number
.
napi_get_value_bigint_int64#
napi_status napi_get_value_bigint_int64(napi_env env,
napi_value value,
int64_t* result,
bool* lossless);
[in] env
: The environment that the API is invoked under[in] value
:napi_value
representing JavaScriptBigInt
.[out] result
: Cint64_t
primitive equivalent of the given JavaScriptBigInt
.[out] lossless
: Indicates whether theBigInt
value was converted losslessly.
Returns napi_ok
if the API succeeded. If a non-BigInt
is passed in it
returns napi_bigint_expected
.
This API returns the C int64_t
primitive equivalent of the given JavaScript
BigInt
. If needed it will truncate the value, setting lossless
to false
.
napi_get_value_bigint_uint64#
napi_status napi_get_value_bigint_uint64(napi_env env,
napi_value value,
uint64_t* result,
bool* lossless);
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptBigInt
.[out] result
: Cuint64_t
primitive equivalent of the given JavaScriptBigInt
.[out] lossless
: Indicates whether theBigInt
value was converted losslessly.
Returns napi_ok
if the API succeeded. If a non-BigInt
is passed in it
returns napi_bigint_expected
.
This API returns the C uint64_t
primitive equivalent of the given JavaScript
BigInt
. If needed it will truncate the value, setting lossless
to false
.
napi_get_value_bigint_words#
napi_status napi_get_value_bigint_words(napi_env env,
napi_value value,
int* sign_bit,
size_t* word_count,
uint64_t* words);
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptBigInt
.[out] sign_bit
: Integer representing if the JavaScriptBigInt
is positive or negative.[in/out] word_count
: Must be initialized to the length of thewords
array. Upon return, it will be set to the actual number of words that would be needed to store thisBigInt
.[out] words
: Pointer to a pre-allocated 64-bit word array.
Returns napi_ok
if the API succeeded.
This API converts a single BigInt
value into a sign bit, 64-bit little-endian
array, and the number of elements in the array. sign_bit
and words
may be
both set to NULL
, in order to get only word_count
.
napi_get_value_external#
napi_status napi_get_value_external(napi_env env,
napi_value value,
void** result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScript external value.[out] result
: Pointer to the data wrapped by the JavaScript external value.
Returns napi_ok
if the API succeeded. If a non-external napi_value
is
passed in it returns napi_invalid_arg
.
This API retrieves the external data pointer that was previously passed to
napi_create_external()
.
napi_get_value_int32#
napi_status napi_get_value_int32(napi_env env,
napi_value value,
int32_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptNumber
.[out] result
: Cint32
primitive equivalent of the given JavaScriptNumber
.
Returns napi_ok
if the API succeeded. If a non-number napi_value
is passed in napi_number_expected
.
This API returns the C int32
primitive equivalent
of the given JavaScript Number
.
If the number exceeds the range of the 32 bit integer, then the result is truncated to the equivalent of the bottom 32 bits. This can result in a large positive number becoming a negative number if the value is > 231 - 1.
Non-finite number values (NaN
, +Infinity
, or -Infinity
) set the
result to zero.
napi_get_value_int64#
napi_status napi_get_value_int64(napi_env env,
napi_value value,
int64_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptNumber
.[out] result
: Cint64
primitive equivalent of the given JavaScriptNumber
.
Returns napi_ok
if the API succeeded. If a non-number napi_value
is passed in it returns napi_number_expected
.
This API returns the C int64
primitive equivalent of the given JavaScript
Number
.
Number
values outside the range of Number.MIN_SAFE_INTEGER
-(2**53 - 1)
- Number.MAX_SAFE_INTEGER
(2**53 - 1)
will lose
precision.
Non-finite number values (NaN
, +Infinity
, or -Infinity
) set the
result to zero.
napi_get_value_string_latin1#
napi_status napi_get_value_string_latin1(napi_env env,
napi_value value,
char* buf,
size_t bufsize,
size_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScript string.[in] buf
: Buffer to write the ISO-8859-1-encoded string into. IfNULL
is passed in, the length of the string (in bytes) is returned.[in] bufsize
: Size of the destination buffer. When this value is insufficient, the returned string will be truncated.[out] result
: Number of bytes copied into the buffer, excluding the null terminator.
Returns napi_ok
if the API succeeded. If a non-String
napi_value
is passed in it returns napi_string_expected
.
This API returns the ISO-8859-1-encoded string corresponding the value passed in.
napi_get_value_string_utf8#
napi_status napi_get_value_string_utf8(napi_env env,
napi_value value,
char* buf,
size_t bufsize,
size_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScript string.[in] buf
: Buffer to write the UTF8-encoded string into. IfNULL
is passed in, the length of the string (in bytes) is returned.[in] bufsize
: Size of the destination buffer. When this value is insufficient, the returned string will be truncated.[out] result
: Number of bytes copied into the buffer, excluding the null terminator.
Returns napi_ok
if the API succeeded. If a non-String
napi_value
is passed in it returns napi_string_expected
.
This API returns the UTF8-encoded string corresponding the value passed in.
napi_get_value_string_utf16#
napi_status napi_get_value_string_utf16(napi_env env,
napi_value value,
char16_t* buf,
size_t bufsize,
size_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScript string.[in] buf
: Buffer to write the UTF16-LE-encoded string into. IfNULL
is passed in, the length of the string (in 2-byte code units) is returned.[in] bufsize
: Size of the destination buffer. When this value is insufficient, the returned string will be truncated.[out] result
: Number of 2-byte code units copied into the buffer, excluding the null terminator.
Returns napi_ok
if the API succeeded. If a non-String
napi_value
is passed in it returns napi_string_expected
.
This API returns the UTF16-encoded string corresponding the value passed in.
napi_get_value_uint32#
napi_status napi_get_value_uint32(napi_env env,
napi_value value,
uint32_t* result)
[in] env
: The environment that the API is invoked under.[in] value
:napi_value
representing JavaScriptNumber
.[out] result
: C primitive equivalent of the givennapi_value
as auint32_t
.
Returns napi_ok
if the API succeeded. If a non-number napi_value
is passed in it returns napi_number_expected
.
This API returns the C primitive equivalent of the given napi_value
as a
uint32_t
.
Functions to get global instances#
napi_get_boolean#
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: The value of the boolean to retrieve.[out] result
:napi_value
representing JavaScriptBoolean
singleton to retrieve.
Returns napi_ok
if the API succeeded.
This API is used to return the JavaScript singleton object that is used to represent the given boolean value.
napi_get_global#
napi_status napi_get_global(napi_env env, napi_value* result)
[in] env
: The environment that the API is invoked under.[out] result
:napi_value
representing JavaScriptglobal
object.
Returns napi_ok
if the API succeeded.
This API returns the global
object.
napi_get_null#
napi_status napi_get_null(napi_env env, napi_value* result)
[in] env
: The environment that the API is invoked under.[out] result
:napi_value
representing JavaScriptnull
object.
Returns napi_ok
if the API succeeded.
This API returns the null
object.
napi_get_undefined#
napi_status napi_get_undefined(napi_env env, napi_value* result)
[in] env
: The environment that the API is invoked under.[out] result
:napi_value
representing JavaScript Undefined value.
Returns napi_ok
if the API succeeded.
This API returns the Undefined object.
Working with JavaScript values and abstract operations#
N-API exposes a set of APIs to perform some abstract operations on JavaScript values. Some of these operations are documented under Section 7 of the ECMAScript Language Specification.
These APIs support doing one of the following:
- Coerce JavaScript values to specific JavaScript types (such as
Number
orString
). - Check the type of a JavaScript value.
- Check for equality between two JavaScript values.
napi_coerce_to_bool#
napi_status napi_coerce_to_bool(napi_env env,
napi_value value,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to coerce.[out] result
:napi_value
representing the coerced JavaScriptBoolean
.
Returns napi_ok
if the API succeeded.
This API implements the abstract operation ToBoolean()
as defined in
Section 7.1.2 of the ECMAScript Language Specification.
This API can be re-entrant if getters are defined on the passed-in Object
.
napi_coerce_to_number#
napi_status napi_coerce_to_number(napi_env env,
napi_value value,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to coerce.[out] result
:napi_value
representing the coerced JavaScriptNumber
.
Returns napi_ok
if the API succeeded.
This API implements the abstract operation ToNumber()
as defined in
Section 7.1.3 of the ECMAScript Language Specification.
This API can be re-entrant if getters are defined on the passed-in Object
.
napi_coerce_to_object#
napi_status napi_coerce_to_object(napi_env env,
napi_value value,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to coerce.[out] result
:napi_value
representing the coerced JavaScriptObject
.
Returns napi_ok
if the API succeeded.
This API implements the abstract operation ToObject()
as defined in
Section 7.1.13 of the ECMAScript Language Specification.
This API can be re-entrant if getters are defined on the passed-in Object
.
napi_coerce_to_string#
napi_status napi_coerce_to_string(napi_env env,
napi_value value,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to coerce.[out] result
:napi_value
representing the coerced JavaScriptString
.
Returns napi_ok
if the API succeeded.
This API implements the abstract operation ToString()
as defined in
Section 7.1.13 of the ECMAScript Language Specification.
This API can be re-entrant if getters are defined on the passed-in Object
.
napi_typeof#
napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value whose type to query.[out] result
: The type of the JavaScript value.
Returns napi_ok
if the API succeeded.
napi_invalid_arg
if the type ofvalue
is not a known ECMAScript type andvalue
is not an External value.
This API represents behavior similar to invoking the typeof
Operator on
the object as defined in Section 12.5.5 of the ECMAScript Language
Specification. However, there are some differences:
- It has support for detecting an External value.
- It detects
null
as a separate type, while ECMAScripttypeof
would detectobject
.
If value
has a type that is invalid, an error is returned.
napi_instanceof#
napi_status napi_instanceof(napi_env env,
napi_value object,
napi_value constructor,
bool* result)
[in] env
: The environment that the API is invoked under.[in] object
: The JavaScript value to check.[in] constructor
: The JavaScript function object of the constructor function to check against.[out] result
: Boolean that is set to true ifobject instanceof constructor
is true.
Returns napi_ok
if the API succeeded.
This API represents invoking the instanceof
Operator on the object as
defined in Section 12.10.4 of the ECMAScript Language Specification.
napi_is_array#
napi_status napi_is_array(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the given object is an array.
Returns napi_ok
if the API succeeded.
This API represents invoking the IsArray
operation on the object
as defined in Section 7.2.2 of the ECMAScript Language Specification.
napi_is_arraybuffer#
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the given object is anArrayBuffer
.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is an array buffer.
napi_is_buffer#
napi_status napi_is_buffer(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the givennapi_value
represents anode::Buffer
object.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is a buffer.
napi_is_date#
napi_status napi_is_date(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the givennapi_value
represents a JavaScriptDate
object.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is a date.
napi_is_error#
napi_status napi_is_error(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the givennapi_value
represents anError
object.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is an Error
.
napi_is_typedarray#
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the givennapi_value
represents aTypedArray
.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is a typed array.
napi_is_dataview#
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result)
[in] env
: The environment that the API is invoked under.[in] value
: The JavaScript value to check.[out] result
: Whether the givennapi_value
represents aDataView
.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in is a DataView
.
napi_strict_equals#
napi_status napi_strict_equals(napi_env env,
napi_value lhs,
napi_value rhs,
bool* result)
[in] env
: The environment that the API is invoked under.[in] lhs
: The JavaScript value to check.[in] rhs
: The JavaScript value to check against.[out] result
: Whether the twonapi_value
objects are equal.
Returns napi_ok
if the API succeeded.
This API represents the invocation of the Strict Equality algorithm as defined in Section 7.2.14 of the ECMAScript Language Specification.
napi_detach_arraybuffer#
napi_status napi_detach_arraybuffer(napi_env env,
napi_value arraybuffer)
[in] env
: The environment that the API is invoked under.[in] arraybuffer
: The JavaScriptArrayBuffer
to be detached.
Returns napi_ok
if the API succeeded. If a non-detachable ArrayBuffer
is
passed in it returns napi_detachable_arraybuffer_expected
.
Generally, an ArrayBuffer
is non-detachable if it has been detached before.
The engine may impose additional conditions on whether an ArrayBuffer
is
detachable. For example, V8 requires that the ArrayBuffer
be external,
that is, created with napi_create_external_arraybuffer
.
This API represents the invocation of the ArrayBuffer
detach operation as
defined in Section 24.1.1.3 of the ECMAScript Language Specification.
napi_is_detached_arraybuffer#
napi_status napi_is_detached_arraybuffer(napi_env env,
napi_value arraybuffer,
bool* result)
[in] env
: The environment that the API is invoked under.[in] arraybuffer
: The JavaScriptArrayBuffer
to be checked.[out] result
: Whether thearraybuffer
is detached.
Returns napi_ok
if the API succeeded.
The ArrayBuffer
is considered detached if its internal data is null
.
This API represents the invocation of the ArrayBuffer
IsDetachedBuffer
operation as defined in Section 24.1.1.2 of the ECMAScript Language
Specification.
Working with JavaScript properties#
N-API exposes a set of APIs to get and set properties on JavaScript objects. Some of these types are documented under Section 7 of the ECMAScript Language Specification.
Properties in JavaScript are represented as a tuple of a key and a value. Fundamentally, all property keys in N-API can be represented in one of the following forms:
- Named: a simple UTF8-encoded string
- Integer-Indexed: an index value represented by
uint32_t
- JavaScript value: these are represented in N-API by
napi_value
. This can be anapi_value
representing aString
,Number
, orSymbol
.
N-API values are represented by the type napi_value
.
Any N-API call that requires a JavaScript value takes in a napi_value
.
However, it's the caller's responsibility to make sure that the
napi_value
in question is of the JavaScript type expected by the API.
The APIs documented in this section provide a simple interface to
get and set properties on arbitrary JavaScript objects represented by
napi_value
.
For instance, consider the following JavaScript code snippet:
const obj = {};
obj.myProp = 123;
The equivalent can be done using N-API values with the following snippet:
napi_status status = napi_generic_failure;
// const obj = {}
napi_value obj, value;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;
// Create a napi_value for 123
status = napi_create_int32(env, 123, &value);
if (status != napi_ok) return status;
// obj.myProp = 123
status = napi_set_named_property(env, obj, "myProp", value);
if (status != napi_ok) return status;
Indexed properties can be set in a similar manner. Consider the following JavaScript snippet:
const arr = [];
arr[123] = 'hello';
The equivalent can be done using N-API values with the following snippet:
napi_status status = napi_generic_failure;
// const arr = [];
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;
// Create a napi_value for 'hello'
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &value);
if (status != napi_ok) return status;
// arr[123] = 'hello';
status = napi_set_element(env, arr, 123, value);
if (status != napi_ok) return status;
Properties can be retrieved using the APIs described in this section. Consider the following JavaScript snippet:
const arr = [];
const value = arr[123];
The following is the approximate equivalent of the N-API counterpart:
napi_status status = napi_generic_failure;
// const arr = []
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;
// const value = arr[123]
status = napi_get_element(env, arr, 123, &value);
if (status != napi_ok) return status;
Finally, multiple properties can also be defined on an object for performance reasons. Consider the following JavaScript:
const obj = {};
Object.defineProperties(obj, {
'foo': { value: 123, writable: true, configurable: true, enumerable: true },
'bar': { value: 456, writable: true, configurable: true, enumerable: true }
});
The following is the approximate equivalent of the N-API counterpart:
napi_status status = napi_status_generic_failure;
// const obj = {};
napi_value obj;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;
// Create napi_values for 123 and 456
napi_value fooValue, barValue;
status = napi_create_int32(env, 123, &fooValue);
if (status != napi_ok) return status;
status = napi_create_int32(env, 456, &barValue);
if (status != napi_ok) return status;
// Set the properties
napi_property_descriptor descriptors[] = {
{ "foo", NULL, NULL, NULL, NULL, fooValue, napi_writable | napi_configurable, NULL },
{ "bar", NULL, NULL, NULL, NULL, barValue, napi_writable | napi_configurable, NULL }
}
status = napi_define_properties(env,
obj,
sizeof(descriptors) / sizeof(descriptors[0]),
descriptors);
if (status != napi_ok) return status;
Structures#
napi_property_attributes#
typedef enum {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_property = napi_writable |
napi_enumerable |
napi_configurable,
} napi_property_attributes;
napi_property_attributes
are flags used to control the behavior of properties
set on a JavaScript object. Other than napi_static
they correspond to the
attributes listed in Section 6.1.7.1
of the ECMAScript Language Specification.
They can be one or more of the following bitflags:
napi_default
: No explicit attributes are set on the property. By default, a property is read only, not enumerable and not configurable.napi_writable
: The property is writable.napi_enumerable
: The property is enumerable.napi_configurable
: The property is configurable as defined in Section 6.1.7.1 of the ECMAScript Language Specification.napi_static
: The property will be defined as a static property on a class as opposed to an instance property, which is the default. This is used only bynapi_define_class
. It is ignored bynapi_define_properties
.napi_default_method
: The property is configureable, writeable but not enumerable like a method in a JS class.napi_default_property
: The property is writable, enumerable and configurable like a property set via JS codeobj.key = value
.
napi_property_descriptor#
typedef struct {
// One of utf8name or name should be NULL.
const char* utf8name;
napi_value name;
napi_callback method;
napi_callback getter;
napi_callback setter;
napi_value value;
napi_property_attributes attributes;
void* data;
} napi_property_descriptor;
utf8name
: OptionalString
describing the key for the property, encoded as UTF8. One ofutf8name
orname
must be provided for the property.name
: Optionalnapi_value
that points to a JavaScript string or symbol to be used as the key for the property. One ofutf8name
orname
must be provided for the property.value
: The value that's retrieved by a get access of the property if the property is a data property. If this is passed in, setgetter
,setter
,method
anddata
toNULL
(since these members won't be used).getter
: A function to call when a get access of the property is performed. If this is passed in, setvalue
andmethod
toNULL
(since these members won't be used). The given function is called implicitly by the runtime when the property is accessed from JavaScript code (or if a get on the property is performed using a N-API call).napi_callback
provides more details.setter
: A function to call when a set access of the property is performed. If this is passed in, setvalue
andmethod
toNULL
(since these members won't be used). The given function is called implicitly by the runtime when the property is set from JavaScript code (or if a set on the property is performed using a N-API call).napi_callback
provides more details.method
: Set this to make the property descriptor object'svalue
property to be a JavaScript function represented bymethod
. If this is passed in, setvalue
,getter
andsetter
toNULL
(since these members won't be used).napi_callback
provides more details.attributes
: The attributes associated with the particular property. Seenapi_property_attributes
.data
: The callback data passed intomethod
,getter
andsetter
if this function is invoked.
Functions#
napi_get_property_names#
napi_status napi_get_property_names(napi_env env,
napi_value object,
napi_value* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the properties.[out] result
: Anapi_value
representing an array of JavaScript values that represent the property names of the object. The API can be used to iterate overresult
usingnapi_get_array_length
andnapi_get_element
.
Returns napi_ok
if the API succeeded.
This API returns the names of the enumerable properties of object
as an array
of strings. The properties of object
whose key is a symbol will not be
included.
napi_get_all_property_names#
napi_get_all_property_names(napi_env env,
napi_value object,
napi_key_collection_mode key_mode,
napi_key_filter key_filter,
napi_key_conversion key_conversion,
napi_value* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the properties.[in] key_mode
: Whether to retrieve prototype properties as well.[in] key_filter
: Which properties to retrieve (enumerable/readable/writable).[in] key_conversion
: Whether to convert numbered property keys to strings.[out] result
: Anapi_value
representing an array of JavaScript values that represent the property names of the object.napi_get_array_length
andnapi_get_element
can be used to iterate overresult
.
Returns napi_ok
if the API succeeded.
This API returns an array containing the names of the available properties of this object.
napi_set_property#
napi_status napi_set_property(napi_env env,
napi_value object,
napi_value key,
napi_value value);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object on which to set the property.[in] key
: The name of the property to set.[in] value
: The property value.
Returns napi_ok
if the API succeeded.
This API set a property on the Object
passed in.
napi_get_property#
napi_status napi_get_property(napi_env env,
napi_value object,
napi_value key,
napi_value* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the property.[in] key
: The name of the property to retrieve.[out] result
: The value of the property.
Returns napi_ok
if the API succeeded.
This API gets the requested property from the Object
passed in.
napi_has_property#
napi_status napi_has_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] key
: The name of the property whose existence to check.[out] result
: Whether the property exists on the object or not.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in has the named property.
napi_delete_property#
napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] key
: The name of the property to delete.[out] result
: Whether the property deletion succeeded or not.result
can optionally be ignored by passingNULL
.
Returns napi_ok
if the API succeeded.
This API attempts to delete the key
own property from object
.
napi_has_own_property#
napi_status napi_has_own_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] key
: The name of the own property whose existence to check.[out] result
: Whether the own property exists on the object or not.
Returns napi_ok
if the API succeeded.
This API checks if the Object
passed in has the named own property. key
must
be a string or a Symbol
, or an error will be thrown. N-API will not perform
any conversion between data types.
napi_set_named_property#
napi_status napi_set_named_property(napi_env env,
napi_value object,
const char* utf8Name,
napi_value value);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object on which to set the property.[in] utf8Name
: The name of the property to set.[in] value
: The property value.
Returns napi_ok
if the API succeeded.
This method is equivalent to calling napi_set_property
with a napi_value
created from the string passed in as utf8Name
.
napi_get_named_property#
napi_status napi_get_named_property(napi_env env,
napi_value object,
const char* utf8Name,
napi_value* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the property.[in] utf8Name
: The name of the property to get.[out] result
: The value of the property.
Returns napi_ok
if the API succeeded.
This method is equivalent to calling napi_get_property
with a napi_value
created from the string passed in as utf8Name
.
napi_has_named_property#
napi_status napi_has_named_property(napi_env env,
napi_value object,
const char* utf8Name,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] utf8Name
: The name of the property whose existence to check.[out] result
: Whether the property exists on the object or not.
Returns napi_ok
if the API succeeded.
This method is equivalent to calling napi_has_property
with a napi_value
created from the string passed in as utf8Name
.
napi_set_element#
napi_status napi_set_element(napi_env env,
napi_value object,
uint32_t index,
napi_value value);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to set the properties.[in] index
: The index of the property to set.[in] value
: The property value.
Returns napi_ok
if the API succeeded.
This API sets and element on the Object
passed in.
napi_get_element#
napi_status napi_get_element(napi_env env,
napi_value object,
uint32_t index,
napi_value* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the property.[in] index
: The index of the property to get.[out] result
: The value of the property.
Returns napi_ok
if the API succeeded.
This API gets the element at the requested index.
napi_has_element#
napi_status napi_has_element(napi_env env,
napi_value object,
uint32_t index,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] index
: The index of the property whose existence to check.[out] result
: Whether the property exists on the object or not.
Returns napi_ok
if the API succeeded.
This API returns if the Object
passed in has an element at the
requested index.
napi_delete_element#
napi_status napi_delete_element(napi_env env,
napi_value object,
uint32_t index,
bool* result);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to query.[in] index
: The index of the property to delete.[out] result
: Whether the element deletion succeeded or not.result
can optionally be ignored by passingNULL
.
Returns napi_ok
if the API succeeded.
This API attempts to delete the specified index
from object
.
napi_define_properties#
napi_status napi_define_properties(napi_env env,
napi_value object,
size_t property_count,
const napi_property_descriptor* properties);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object from which to retrieve the properties.[in] property_count
: The number of elements in theproperties
array.[in] properties
: The array of property descriptors.
Returns napi_ok
if the API succeeded.
This method allows the efficient definition of multiple properties on a given
object. The properties are defined using property descriptors (see
napi_property_descriptor
). Given an array of such property descriptors,
this API will set the properties on the object one at a time, as defined by
DefineOwnProperty()
(described in Section 9.1.6 of the ECMA-262
specification).
napi_object_freeze#
napi_status napi_object_freeze(napi_env env,
napi_value object);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to freeze.
Returns napi_ok
if the API succeeded.
This method freezes a given object. This prevents new properties from being added to it, existing properties from being removed, prevents changing the enumerability, configurability, or writability of existing properties, and prevents the values of existing properties from being changed. It also prevents the object's prototype from being changed. This is described in Section 19.1.2.6 of the ECMA-262 specification.
napi_object_seal#
napi_status napi_object_seal(napi_env env,
napi_value object);
[in] env
: The environment that the N-API call is invoked under.[in] object
: The object to seal.
Returns napi_ok
if the API succeeded.
This method seals a given object. This prevents new properties from being added to it, as well as marking all existing properties as non-configurable. This is described in Section 19.1.2.20 of the ECMA-262 specification.
Working with JavaScript functions#
N-API provides a set of APIs that allow JavaScript code to
call back into native code. N-API APIs that support calling back
into native code take in a callback functions represented by
the napi_callback
type. When the JavaScript VM calls back to
native code, the napi_callback
function provided is invoked. The APIs
documented in this section allow the callback function to do the
following:
- Get information about the context in which the callback was invoked.
- Get the arguments passed into the callback.
- Return a
napi_value
back from the callback.
Additionally, N-API provides a set of functions which allow calling JavaScript functions from native code. One can either call a function like a regular JavaScript function call, or as a constructor function.
Any non-NULL
data which is passed to this API via the data
field of the
napi_property_descriptor
items can be associated with object
and freed
whenever object
is garbage-collected by passing both object
and the data to
napi_add_finalizer
.
napi_call_function#
NAPI_EXTERN napi_status napi_call_function(napi_env env,
napi_value recv,
napi_value func,
size_t argc,
const napi_value* argv,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] recv
: Thethis
object passed to the called function.[in] func
:napi_value
representing the JavaScript function to be invoked.[in] argc
: The count of elements in theargv
array.[in] argv
: Array ofnapi_values
representing JavaScript values passed in as arguments to the function.[out] result
:napi_value
representing the JavaScript object returned.
Returns napi_ok
if the API succeeded.
This method allows a JavaScript function object to be called from a native
add-on. This is the primary mechanism of calling back from the add-on's
native code into JavaScript. For the special case of calling into JavaScript
after an async operation, see napi_make_callback
.
A sample use case might look as follows. Consider the following JavaScript snippet:
function AddTwo(num) {
return num + 2;
}
Then, the above function can be invoked from a native add-on using the following code:
// Get the function named "AddTwo" on the global object
napi_value global, add_two, arg;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;
status = napi_get_named_property(env, global, "AddTwo", &add_two);
if (status != napi_ok) return;
// const arg = 1337
status = napi_create_int32(env, 1337, &arg);
if (status != napi_ok) return;
napi_value* argv = &arg;
size_t argc = 1;
// AddTwo(arg);
napi_value return_val;
status = napi_call_function(env, global, add_two, argc, argv, &return_val);
if (status != napi_ok) return;
// Convert the result back to a native type
int32_t result;
status = napi_get_value_int32(env, return_val, &result);
if (status != napi_ok) return;
napi_create_function#
napi_status napi_create_function(napi_env env,
const char* utf8name,
size_t length,
napi_callback cb,
void* data,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] utf8Name
: The name of the function encoded as UTF8. This is visible within JavaScript as the new function object'sname
property.[in] length
: The length of theutf8name
in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.[in] cb
: The native function which should be called when this function object is invoked.napi_callback
provides more details.[in] data
: User-provided data context. This will be passed back into the function when invoked later.[out] result
:napi_value
representing the JavaScript function object for the newly created function.
Returns napi_ok
if the API succeeded.
This API allows an add-on author to create a function object in native code. This is the primary mechanism to allow calling into the add-on's native code from JavaScript.
The newly created function is not automatically visible from script after this call. Instead, a property must be explicitly set on any object that is visible to JavaScript, in order for the function to be accessible from script.
In order to expose a function as part of the add-on's module exports, set the newly created function on the exports object. A sample module might look as follows:
napi_value SayHello(napi_env env, napi_callback_info info) {
printf("Hello\n");
return NULL;
}
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_value fn;
status = napi_create_function(env, NULL, 0, SayHello, NULL, &fn);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "sayHello", fn);
if (status != napi_ok) return NULL;
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
Given the above code, the add-on can be used from JavaScript as follows:
const myaddon = require('./addon');
myaddon.sayHello();
The string passed to require()
is the name of the target in binding.gyp
responsible for creating the .node
file.
Any non-NULL
data which is passed to this API via the data
parameter can
be associated with the resulting JavaScript function (which is returned in the
result
parameter) and freed whenever the function is garbage-collected by
passing both the JavaScript function and the data to napi_add_finalizer
.
JavaScript Function
s are described in Section 19.2 of the ECMAScript
Language Specification.
napi_get_cb_info#
napi_status napi_get_cb_info(napi_env env,
napi_callback_info cbinfo,
size_t* argc,
napi_value* argv,
napi_value* thisArg,
void** data)
[in] env
: The environment that the API is invoked under.[in] cbinfo
: The callback info passed into the callback function.[in-out] argc
: Specifies the size of the providedargv
array and receives the actual count of arguments.[out] argv
: Buffer to which thenapi_value
representing the arguments are copied. If there are more arguments than the provided count, only the requested number of arguments are copied. If there are fewer arguments provided than claimed, the rest ofargv
is filled withnapi_value
values that representundefined
.[out] this
: Receives the JavaScriptthis
argument for the call.[out] data
: Receives the data pointer for the callback.
Returns napi_ok
if the API succeeded.
This method is used within a callback function to retrieve details about the
call like the arguments and the this
pointer from a given callback info.
napi_get_new_target#
napi_status napi_get_new_target(napi_env env,
napi_callback_info cbinfo,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] cbinfo
: The callback info passed into the callback function.[out] result
: Thenew.target
of the constructor call.
Returns napi_ok
if the API succeeded.
This API returns the new.target
of the constructor call. If the current
callback is not a constructor call, the result is NULL
.
napi_new_instance#
napi_status napi_new_instance(napi_env env,
napi_value cons,
size_t argc,
napi_value* argv,
napi_value* result)
[in] env
: The environment that the API is invoked under.[in] cons
:napi_value
representing the JavaScript function to be invoked as a constructor.[in] argc
: The count of elements in theargv
array.[in] argv
: Array of JavaScript values asnapi_value
representing the arguments to the constructor.[out] result
:napi_value
representing the JavaScript object returned, which in this case is the constructed object.
This method is used to instantiate a new JavaScript value using a given
napi_value
that represents the constructor for the object. For example,
consider the following snippet:
function MyObject(param) {
this.param = param;
}
const arg = 'hello';
const value = new MyObject(arg);
The following can be approximated in N-API using the following snippet:
// Get the constructor function MyObject
napi_value global, constructor, arg, value;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;
status = napi_get_named_property(env, global, "MyObject", &constructor);
if (status != napi_ok) return;
// const arg = "hello"
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &arg);
if (status != napi_ok) return;
napi_value* argv = &arg;
size_t argc = 1;
// const value = new MyObject(arg)
status = napi_new_instance(env, constructor, argc, argv, &value);
Returns napi_ok
if the API succeeded.
Object wrap#
N-API offers a way to "wrap" C++ classes and instances so that the class constructor and methods can be called from JavaScript.
- The
napi_define_class
API defines a JavaScript class with constructor, static properties and methods, and instance properties and methods that correspond to the C++ class. - When JavaScript code invokes the constructor, the constructor callback
uses
napi_wrap
to wrap a new C++ instance in a JavaScript object, then returns the wrapper object. - When JavaScript code invokes a method or property accessor on the class,
the corresponding
napi_callback
C++ function is invoked. For an instance callback,napi_unwrap
obtains the C++ instance that is the target of the call.
For wrapped objects it may be difficult to distinguish between a function
called on a class prototype and a function called on an instance of a class.
A common pattern used to address this problem is to save a persistent
reference to the class constructor for later instanceof
checks.
napi_value MyClass_constructor = NULL;
status = napi_get_reference_value(env, MyClass::es_constructor, &MyClass_constructor);
assert(napi_ok == status);
bool is_instance = false;
status = napi_instanceof(env, es_this, MyClass_constructor, &is_instance);
assert(napi_ok == status);
if (is_instance) {
// napi_unwrap() ...
} else {
// otherwise...
}
The reference must be freed once it is no longer needed.
There are occasions where napi_instanceof()
is insufficient for ensuring that
a JavaScript object is a wrapper for a certain native type. This is the case
especially when wrapped JavaScript objects are passed back into the addon via
static methods rather than as the this
value of prototype methods. In such
cases there is a chance that they may be unwrapped incorrectly.
const myAddon = require('./build/Release/my_addon.node');
// `openDatabase()` returns a JavaScript object that wraps a native database
// handle.
const dbHandle = myAddon.openDatabase();
// `query()` returns a JavaScript object that wraps a native query handle.
const queryHandle = myAddon.query(dbHandle, 'Gimme ALL the things!');
// There is an accidental error in the line below. The first parameter to
// `myAddon.queryHasRecords()` should be the database handle (`dbHandle`), not
// the query handle (`query`), so the correct condition for the while-loop
// should be
//
// myAddon.queryHasRecords(dbHandle, queryHandle)
//
while (myAddon.queryHasRecords(queryHandle, dbHandle)) {
// retrieve records
}
In the above example myAddon.queryHasRecords()
is a method that accepts two
arguments. The first is a database handle and the second is a query handle.
Internally, it unwraps the first argument and casts the resulting pointer to a
native database handle. It then unwraps the second argument and casts the
resulting pointer to a query handle. If the arguments are passed in the wrong
order, the casts will work, however, there is a good chance that the underlying
database operation will fail, or will even cause an invalid memory access.
To ensure that the pointer retrieved from the first argument is indeed a pointer
to a database handle and, similarly, that the pointer retrieved from the second
argument is indeed a pointer to a query handle, the implementation of
queryHasRecords()
has to perform a type validation. Retaining the JavaScript
class constructor from which the database handle was instantiated and the
constructor from which the query handle was instantiated in napi_ref
s can
help, because napi_instanceof()
can then be used to ensure that the instances
passed into queryHashRecords()
are indeed of the correct type.
Unfortunately, napi_instanceof()
does not protect against prototype
manipulation. For example, the prototype of the database handle instance can be
set to the prototype of the constructor for query handle instances. In this
case, the database handle instance can appear as a query handle instance, and it
will pass the napi_instanceof()
test for a query handle instance, while still
containing a pointer to a database handle.
To this end, N-API provides type-tagging capabilities.
A type tag is a 128-bit integer unique to the addon. N-API provides the
napi_type_tag
structure for storing a type tag. When such a value is passed
along with a JavaScript object stored in a napi_value
to
napi_type_tag_object()
, the JavaScript object will be "marked" with the
type tag. The "mark" is invisible on the JavaScript side. When a JavaScript
object arrives into a native binding, napi_check_object_type_tag()
can be used
along with the original type tag to determine whether the JavaScript object was
previously "marked" with the type tag. This creates a type-checking capability
of a higher fidelity than napi_instanceof()
can provide, because such type-
tagging survives prototype manipulation and addon unloading/reloading.
Continuing the above example, the following skeleton addon implementation
illustrates the use of napi_type_tag_object()
and
napi_check_object_type_tag()
.
// This value is the type tag for a database handle. The command
//
// uuidgen | sed -r -e 's/-//g' -e 's/(.{16})(.*)/0x\1, 0x\2/'
//
// can be used to obtain the two values with which to initialize the structure.
static const napi_type_tag DatabaseHandleTypeTag = {
0x1edf75a38336451d, 0xa5ed9ce2e4c00c38
};
// This value is the type tag for a query handle.
static const napi_type_tag QueryHandleTypeTag = {
0x9c73317f9fad44a3, 0x93c3920bf3b0ad6a
};
static napi_value
openDatabase(napi_env env, napi_callback_info info) {
napi_status status;
napi_value result;
// Perform the underlying action which results in a database handle.
DatabaseHandle* dbHandle = open_database();
// Create a new, empty JS object.
status = napi_create_object(env, &result);
if (status != napi_ok) return NULL;
// Tag the object to indicate that it holds a pointer to a `DatabaseHandle`.
status = napi_type_tag_object(env, result, &DatabaseHandleTypeTag);
if (status != napi_ok) return NULL;
// Store the pointer to the `DatabaseHandle` structure inside the JS object.
status = napi_wrap(env, result, dbHandle, NULL, NULL, NULL);
if (status != napi_ok) return NULL;
return result;
}
// Later when we receive a JavaScript object purporting to be a database handle
// we can use `napi_check_object_type_tag()` to ensure that it is indeed such a
// handle.
static napi_value
query(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 2;
napi_value argv[2];
bool is_db_handle;
status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
if (status != napi_ok) return NULL;
// Check that the object passed as the first parameter has the previously
// applied tag.
status = napi_check_object_type_tag(env,
argv[0],
&DatabaseHandleTypeTag,
&is_db_handle);
if (status != napi_ok) return NULL;
// Throw a `TypeError` if it doesn't.
if (!is_db_handle) {
// Throw a TypeError.
return NULL;
}
}
napi_define_class#
napi_status napi_define_class(napi_env env,
const char* utf8name,
size_t length,
napi_callback constructor,
void* data,
size_t property_count,
const napi_property_descriptor* properties,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] utf8name
: Name of the JavaScript constructor function; this is not required to be the same as the C++ class name, though it is recommended for clarity.[in] length
: The length of theutf8name
in bytes, orNAPI_AUTO_LENGTH
if it is null-terminated.[in] constructor
: Callback function that handles constructing instances of the class. This should be a static method on the class, not an actual C++ constructor function.napi_callback
provides more details.[in] data
: Optional data to be passed to the constructor callback as thedata
property of the callback info.[in] property_count
: Number of items in theproperties
array argument.[in] properties
: Array of property descriptors describing static and instance data properties, accessors, and methods on the class Seenapi_property_descriptor
.[out] result
: Anapi_value
representing the constructor function for the class.
Returns napi_ok
if the API succeeded.
Defines a JavaScript class that corresponds to a C++ class, including:
- A JavaScript constructor function that has the class name and invokes the provided C++ constructor callback.
- Properties on the constructor function corresponding to static data
properties, accessors, and methods of the C++ class (defined by
property descriptors with the
napi_static
attribute). - Properties on the constructor function's
prototype
object corresponding to non-static data properties, accessors, and methods of the C++ class (defined by property descriptors without thenapi_static
attribute).
The C++ constructor callback should be a static method on the class that calls
the actual class constructor, then wraps the new C++ instance in a JavaScript
object, and returns the wrapper object. See napi_wrap()
for details.
The JavaScript constructor function returned from napi_define_class
is
often saved and used later, to construct new instances of the class from native
code, and/or check whether provided values are instances of the class. In that
case, to prevent the function value from being garbage-collected, create a
persistent reference to it using napi_create_reference
and ensure the
reference count is kept >= 1.
Any non-NULL
data which is passed to this API via the data
parameter or via
the data
field of the napi_property_descriptor
array items can be associated
with the resulting JavaScript constructor (which is returned in the result
parameter) and freed whenever the class is garbage-collected by passing both
the JavaScript function and the data to napi_add_finalizer
.
napi_wrap#
napi_status napi_wrap(napi_env env,
napi_value js_object,
void* native_object,
napi_finalize finalize_cb,
void* finalize_hint,
napi_ref* result);
[in] env
: The environment that the API is invoked under.[in] js_object
: The JavaScript object that will be the wrapper for the native object.[in] native_object
: The native instance that will be wrapped in the JavaScript object.[in] finalize_cb
: Optional native callback that can be used to free the native instance when the JavaScript object is ready for garbage-collection.napi_finalize
provides more details.[in] finalize_hint
: Optional contextual hint that is passed to the finalize callback.[out] result
: Optional reference to the wrapped object.
Returns napi_ok
if the API succeeded.
Wraps a native instance in a JavaScript object. The native instance can be
retrieved later using napi_unwrap()
.
When JavaScript code invokes a constructor for a class that was defined using
napi_define_class()
, the napi_callback
for the constructor is invoked.
After constructing an instance of the native class, the callback must then call
napi_wrap()
to wrap the newly constructed instance in the already-created
JavaScript object that is the this
argument to the constructor callback.
(That this
object was created from the constructor function's prototype
,
so it already has definitions of all the instance properties and methods.)
Typically when wrapping a class instance, a finalize callback should be
provided that simply deletes the native instance that is received as the data
argument to the finalize callback.
The optional returned reference is initially a weak reference, meaning it has a reference count of 0. Typically this reference count would be incremented temporarily during async operations that require the instance to remain valid.
Caution: The optional returned reference (if obtained) should be deleted via
napi_delete_reference
ONLY in response to the finalize callback
invocation. If it is deleted before then, then the finalize callback may never
be invoked. Therefore, when obtaining a reference a finalize callback is also
required in order to enable correct disposal of the reference.
Calling napi_wrap()
a second time on an object will return an error. To
associate another native instance with the object, use napi_remove_wrap()
first.
napi_unwrap#
napi_status napi_unwrap(napi_env env,
napi_value js_object,
void** result);
[in] env
: The environment that the API is invoked under.[in] js_object
: The object associated with the native instance.[out] result
: Pointer to the wrapped native instance.
Returns napi_ok
if the API succeeded.
Retrieves a native instance that was previously wrapped in a JavaScript
object using napi_wrap()
.
When JavaScript code invokes a method or property accessor on the class, the
corresponding napi_callback
is invoked. If the callback is for an instance
method or accessor, then the this
argument to the callback is the wrapper
object; the wrapped C++ instance that is the target of the call can be obtained
then by calling napi_unwrap()
on the wrapper object.
napi_remove_wrap#
napi_status napi_remove_wrap(napi_env env,
napi_value js_object,
void** result);
[in] env
: The environment that the API is invoked under.[in] js_object
: The object associated with the native instance.[out] result
: Pointer to the wrapped native instance.
Returns napi_ok
if the API succeeded.
Retrieves a native instance that was previously wrapped in the JavaScript
object js_object
using napi_wrap()
and removes the wrapping. If a finalize
callback was associated with the wrapping, it will no longer be called when the
JavaScript object becomes garbage-collected.
napi_type_tag_object#
napi_status napi_type_tag_object(napi_env env,
napi_value js_object,
const napi_type_tag* type_tag);
[in] env
: The environment that the API is invoked under.[in] js_object
: The JavaScript object to be marked.[in] type_tag
: The tag with which the object is to be marked.
Returns napi_ok
if the API succeeded.
Associates the value of the type_tag
pointer with the JavaScript object.
napi_check_object_type_tag()
can then be used to compare the tag that was
attached to the object with one owned by the addon to ensure that the object
has the right type.
If the object already has an associated type tag, this API will return
napi_invalid_arg
.
napi_check_object_type_tag#
napi_status napi_check_object_type_tag(napi_env env,
napi_value js_object,
const napi_type_tag* type_tag,
bool* result);
[in] env
: The environment that the API is invoked under.[in] js_object
: The JavaScript object whose type tag to examine.[in] type_tag
: The tag with which to compare any tag found on the object.[out] result
: Whether the type tag given matched the type tag on the object.false
is also returned if no type tag was found on the object.
Returns napi_ok
if the API succeeded.
Compares the pointer given as type_tag
with any that can be found on
js_object
. If no tag is found on js_object
or, if a tag is found but it does
not match type_tag
, then result
is set to false
. If a tag is found and it
matches type_tag
, then result
is set to true
.
napi_add_finalizer#
napi_status napi_add_finalizer(napi_env env,
napi_value js_object,
void* native_object,
napi_finalize finalize_cb,
void* finalize_hint,
napi_ref* result);
[in] env
: The environment that the API is invoked under.[in] js_object
: The JavaScript object to which the native data will be attached.[in] native_object
: The native data that will be attached to the JavaScript object.[in] finalize_cb
: Native callback that will be used to free the native data when the JavaScript object is ready for garbage-collection.napi_finalize
provides more details.[in] finalize_hint
: Optional contextual hint that is passed to the finalize callback.[out] result
: Optional reference to the JavaScript object.
Returns napi_ok
if the API succeeded.
Adds a napi_finalize
callback which will be called when the JavaScript object
in js_object
is ready for garbage collection. This API is similar to
napi_wrap()
except that:
- the native data cannot be retrieved later using
napi_unwrap()
, - nor can it be removed later using
napi_remove_wrap()
, and - the API can be called multiple times with different data items in order to attach each of them to the JavaScript object, and
- the object manipulated by the API can be used with
napi_wrap()
.
Caution: The optional returned reference (if obtained) should be deleted via
napi_delete_reference
ONLY in response to the finalize callback
invocation. If it is deleted before then, then the finalize callback may never
be invoked. Therefore, when obtaining a reference a finalize callback is also
required in order to enable correct disposal of the reference.
Simple asynchronous operations#
Addon modules often need to leverage async helpers from libuv as part of their implementation. This allows them to schedule work to be executed asynchronously so that their methods can return in advance of the work being completed. This allows them to avoid blocking overall execution of the Node.js application.
N-API provides an ABI-stable interface for these supporting functions which covers the most common asynchronous use cases.
N-API defines the napi_async_work
structure which is used to manage
asynchronous workers. Instances are created/deleted with
napi_create_async_work
and napi_delete_async_work
.
The execute
and complete
callbacks are functions that will be
invoked when the executor is ready to execute and when it completes its
task respectively.
The execute
function should avoid making any N-API calls
that could result in the execution of JavaScript or interaction with
JavaScript objects. Most often, any code that needs to make N-API
calls should be made in complete
callback instead.
Avoid using the napi_env
parameter in the execute callback as
it will likely execute JavaScript.
These functions implement the following interfaces:
typedef void (*napi_async_execute_callback)(napi_env env,
void* data);
typedef void (*napi_async_complete_callback)(napi_env env,
napi_status status,
void* data);
When these methods are invoked, the data
parameter passed will be the
addon-provided void*
data that was passed into the
napi_create_async_work
call.
Once created the async worker can be queued
for execution using the napi_queue_async_work
function:
napi_status napi_queue_async_work(napi_env env,
napi_async_work work);
napi_cancel_async_work
can be used if the work needs
to be cancelled before the work has started execution.
After calling napi_cancel_async_work
, the complete
callback
will be invoked with a status value of napi_cancelled
.
The work should not be deleted before the complete
callback invocation, even when it was cancelled.
napi_create_async_work#
napi_status napi_create_async_work(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_execute_callback execute,
napi_async_complete_callback complete,
void* data,
napi_async_work* result);
[in] env
: The environment that the API is invoked under.[in] async_resource
: An optional object associated with the async work that will be passed to possibleasync_hooks
init
hooks.[in] async_resource_name
: Identifier for the kind of resource that is being provided for diagnostic information exposed by theasync_hooks
API.[in] execute
: The native function which should be called to execute the logic asynchronously. The given function is called from a worker pool thread and can execute in parallel with the main event loop thread.[in] complete
: The native function which will be called when the asynchronous logic is completed or is cancelled. The given function is called from the main event loop thread.napi_async_complete_callback
provides more details.[in] data
: User-provided data context. This will be passed back into the execute and complete functions.[out] result
:napi_async_work*
which is the handle to the newly created async work.
Returns napi_ok
if the API succeeded.
This API allocates a work object that is used to execute logic asynchronously.
It should be freed using napi_delete_async_work
once the work is no longer
required.
async_resource_name
should be a null-terminated, UTF-8-encoded string.
The async_resource_name
identifier is provided by the user and should be
representative of the type of async work being performed. It is also recommended
to apply namespacing to the identifier, e.g. by including the module name. See
the async_hooks
documentation for more information.
napi_delete_async_work#
napi_status napi_delete_async_work(napi_env env,
napi_async_work work);
[in] env
: The environment that the API is invoked under.[in] work
: The handle returned by the call tonapi_create_async_work
.
Returns napi_ok
if the API succeeded.
This API frees a previously allocated work object.
This API can be called even if there is a pending JavaScript exception.
napi_queue_async_work#
napi_status napi_queue_async_work(napi_env env,
napi_async_work work);
[in] env
: The environment that the API is invoked under.[in] work
: The handle returned by the call tonapi_create_async_work
.
Returns napi_ok
if the API succeeded.
This API requests that the previously allocated work be scheduled
for execution. Once it returns successfully, this API must not be called again
with the same napi_async_work
item or the result will be undefined.
napi_cancel_async_work#
napi_status napi_cancel_async_work(napi_env env,
napi_async_work work);
[in] env
: The environment that the API is invoked under.[in] work
: The handle returned by the call tonapi_create_async_work
.
Returns napi_ok
if the API succeeded.
This API cancels queued work if it has not yet
been started. If it has already started executing, it cannot be
cancelled and napi_generic_failure
will be returned. If successful,
the complete
callback will be invoked with a status value of
napi_cancelled
. The work should not be deleted before the complete
callback invocation, even if it has been successfully cancelled.
This API can be called even if there is a pending JavaScript exception.
Custom asynchronous operations#
The simple asynchronous work APIs above may not be appropriate for every scenario. When using any other asynchronous mechanism, the following APIs are necessary to ensure an asynchronous operation is properly tracked by the runtime.
napi_async_init#
napi_status napi_async_init(napi_env env,
napi_value async_resource,
napi_value async_resource_name,
napi_async_context* result)
[in] env
: The environment that the API is invoked under.[in] async_resource
: Object associated with the async work that will be passed to possibleasync_hooks
init
hooks. In order to retain ABI compatibility with previous versions, passingNULL
forasync_resource
will not result in an error, however, this will result incorrect operation of async hooks for the napi_async_context created. Potential issues include loss of async context when using the AsyncLocalStorage API.[in] async_resource_name
: Identifier for the kind of resource that is being provided for diagnostic information exposed by theasync_hooks
API.[out] result
: The initialized async context.
Returns napi_ok
if the API succeeded.
napi_async_destroy#
napi_status napi_async_destroy(napi_env env,
napi_async_context async_context);
[in] env
: The environment that the API is invoked under.[in] async_context
: The async context to be destroyed.
Returns napi_ok
if the API succeeded.
This API can be called even if there is a pending JavaScript exception.
napi_make_callback#
NAPI_EXTERN napi_status napi_make_callback(napi_env env,
napi_async_context async_context,
napi_value recv,
napi_value func,
size_t argc,
const napi_value* argv,
napi_value* result);
[in] env
: The environment that the API is invoked under.[in] async_context
: Context for the async operation that is invoking the callback. This should normally be a value previously obtained fromnapi_async_init
. HoweverNULL
is also allowed, which indicates the current async context (if any) is to be used for the callback.[in] recv
: Thethis
object passed to the called function.[in] func
:napi_value
representing the JavaScript function to be invoked.[in] argc
: The count of elements in theargv
array.[in] argv
: Array of JavaScript values asnapi_value
representing the arguments to the function.[out] result
:napi_value
representing the JavaScript object returned.
Returns napi_ok
if the API succeeded.
This method allows a JavaScript function object to be called from a native
add-on. This API is similar to napi_call_function
. However, it is used to call
from native code back into JavaScript after returning from an async
operation (when there is no other script on the stack). It is a fairly simple
wrapper around node::MakeCallback
.
Note it is not necessary to use napi_make_callback
from within a
napi_async_complete_callback
; in that situation the callback's async
context has already been set up, so a direct call to napi_call_function
is sufficient and appropriate. Use of the napi_make_callback
function
may be required when implementing custom async behavior that does not use
napi_create_async_work
.
Any process.nextTick
s or Promises scheduled on the microtask queue by
JavaScript dur