I'm trying to get JavaScript to read/write to a PostgreSQL database. I found this project on GitHub. I was able to get the following sample code to run in Node.
var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234@localhost/postgres";
var client = new pg.Client(conString);
client.connect();
//queries are queued and executed one after another once the connection becomes available
client.query("CREATE TEMP TABLE beatles(name varchar(10), height integer, birthday timestamptz)");
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['Ringo', 67, new Date(1945, 11, 2)]);
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['John', 68, new Date(1944, 10, 13)]);
//queries can be executed either via text/parameter values passed as individual arguments
//or by passing an options object containing text, (optional) parameter values, and (optional) query name
client.query({
name: 'insert beatle',
text: "INSERT INTO beatles(name, height, birthday) values($1, $2, $3)",
values: ['George', 70, new Date(1946, 02, 14)]
});
//subsequent queries with the same name will be executed without re-parsing the query plan by postgres
client.query({
name: 'insert beatle',
values: ['Paul', 63, new Date(1945, 04, 03)]
});
var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);
//can stream row results back 1 at a time
query.on('row', function(row) {
console.log(row);
console.log("Beatle name: %s", row.name); //Beatle name: John
console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
});
//fired after last row is emitted
query.on('end', function() {
client.end();
});
Next I tried to make it run on a webpage, but nothing seemed to happen. I checked on the JavaScript console and it just says "require not defined".
So what is this "require"? Why does it work in Node but not in a webpage?
Also, before I got it to work in Node, I had to do npm install pg
. What's that about? I looked in the directory and didn't find a file pg. Where did it put it, and how does JavaScript find it?
7条答案
按热度按时间uqdfh47h1#
You know how when you are running JavaScript in the browser, you have access to variables like "window" or Math? You do not have to declare these variables, they have been written for you to use whenever you want.
Well, when you are running a file in the Node.js environment, there is a variable that you can use. It is called "module" It is an object. It has a property called "exports." And it works like this:
In a file that we will name example.js, you write:
example.js
Now, you want this string "some code" in another file.
We will name the other file otherFile.js
In this file, you write:
otherFile.js
That require() statement goes to the file that you put inside of it, finds whatever data is stored on the module.exports property. The let str = ... part of your code means that whatever that require statement returns is stored to the str variable.
So, in this example, the end-result is that in otherFile.js you now have this:
let string = "some code";
let str = ('./example.js').module.exports
Note:
the file-name that is written inside of the require statement: If it is a local file, it should be the file-path to example.js. Also, the .js extension is added by default, so I didn't have to write it.
You do something similar when requiring node.js libraries, such as Express. In the express.js file, there is an object named 'module', with a property named 'exports'.
So, it looks something like along these lines, under the hood (I am somewhat of a beginner so some of these details might not be exact, but it's to show the concept:
express.js
If you are requiring a module, it looks like this: const moduleName = require("module-name");
If you are requiring a local file, it looks like this: const localFile = require("./path/to/local-file");
(notice the ./ at the beginning of the file name)
Also note that by default, the export is an object .. eg module.exports = {} So, you can write module.exports.myfunction = () => {} before assigning a value to the module.exports. But you can also replace the object by writing module.exports = "I am not an object anymore."
x6492ojm2#
Two flavours of module.exports / require:
(see here )
Flavour 1
export file (misc.js):
other file:
Flavour 2
export file (user.js):
other file:
f0brbegy3#
So what is this "require?"
require()
is not part of the standard JavaScript API. But in Node.js, it's a built-in function with a special purpose: to load modules.Modules are a way to split an application into separate files instead of having all of your application in one file. This concept is also present in other languages with minor differences in syntax and behavior, like C's
include
, Python'simport
, and so on.One big difference between Node.js modules and browser JavaScript is how one script's code is accessed from another script's code.
<script>
element. When they execute, they all have direct access to the global scope, a "shared space" among all scripts. Any script can freely define/modify/remove/call anything on the global scope.exports
ormodule.exports
. For a module to access another module'sexports
ormodule.exports
, it must userequire()
.In your code,
var pg = require('pg');
loads thepg
module, a PostgreSQL client for Node.js. This allows your code to access functionality of the PostgreSQL client's APIs via thepg
variable.Why does it work in node but not in a webpage?
require()
,module.exports
andexports
are APIs of a module system that is specific to Node.js. Browsers do not implement this module system.Also, before I got it to work in node, I had to do
npm install pg
. What's that about?NPM is a package repository service that hosts published JavaScript modules.
npm install
is a command that lets you download packages from their repository.Where did it put it, and how does Javascript find it?
The npm cli puts all the downloaded modules in a
node_modules
directory where you rannpm install
. Node.js has very detailed documentation on how modules find other modules which includes finding anode_modules
directory.im9ewurl4#
Alright, so let's first start with making the distinction between Javascript in a web browser, and Javascript on a server (CommonJS and Node).
Javascript is a language traditionally confined to a web browser with a limited global context defined mostly by what came to be known as the Document Object Model (DOM) level 0 (the Netscape Navigator Javascript API).
Server-side Javascript eliminates that restriction and allows Javascript to call into various pieces of native code (like the Postgres library) and open sockets.
Now
require()
is a special function call defined as part of the CommonJS spec. In node, it resolves libraries and modules in the Node search path, now usually defined asnode_modules
in the same directory (or the directory of the invoked javascript file) or the system-wide search path.To try to answer the rest of your question, we need to use a proxy between the code running in the the browser and the database server.
Since we are discussing Node and you are already familiar with how to run a query from there, it would make sense to use Node as that proxy.
As a simple example, we're going to make a URL that returns a few facts about a Beatle, given a name, as JSON.
8gsdolmq5#
I noticed that whilst the other answers explained what require is and that it is used to load modules in Node they did not give a full reply on how to load node modules when working in the Browser.
It is quite simple to do. Install your module using npm as you describe, and the module itself will be located in a folder usually called node_modules.
Now the simplest way to load it into your app is to reference it from your html with a script tag which points at this directory. i.e if your node_modules directory is in the root of the project at the same level as your index.html you would write this in your index.html:
That whole script will now be loaded into the page - so you can access its variables and methods directly.
There are other approaches which are more widely used in larger projects, such as a module loader like require.js . Of the two, I have not used Require myself, but I think it is considered by many people the way to go.
9rbhqvlz6#
它是用来加载模块的,让我们举一个简单的例子。
在文件
circle_object.js
中:我们可以通过
require
使用它,例如:require()
方法用于加载和缓存JavaScript模块,因此,如果要将本地的相对JavaScript模块加载到Node.js应用程序中,只需使用require()
方法即可。示例:
e5nszbig7#
Necromancing.
IMHO, the existing answers leave much to be desired.
At first, it's very confusing.
You have a (nowhere defined) function "require", which is used to get modules.
And in said (CommonJS) modules, you can use
require, exports and module
,WITHOUT THEM EVER BEING DEFINED.
Not that it would be new that you could use undefined variables in JS, but you couldn't use an undefined function.
So it looks a little like magic at first.
But all magic is based on deception.
When you dig a little deeper, it turns out it is really quite simple:
Require is simply a (non-standard) function defined at global scope .
(global scope = window-object in browser, global-object in NodeJS ).
Note that by default, the "require function" is only implemented in NodeJS, not in the browser.
Also, note that to add to the confusion, for the browser, there is RequireJS , which, despite the name containing the characters "require", RequireJS absolutely does NOT implement require/CommonJS - instead RequireJS implements AMD, which is something similar, but not the same (aka incompatible).
That last one is just one important thing you have to realize on your way to understanding require.
Now, as such, to answer the question "what is require", we "simply" need to know what this function does.
This is perhaps best explained with code.
Here's a simple implementation by Michele Nasti , the code you can find on his github page .
Let's call our minimalisc implementation of the require function "myRequire":
Now you notice, the object "fs" is used here.
For simplicity's sake, Michele just imported the NodeJS fs module:
Which wouldn't be necessary.
So in the browser, you could make a simple implementation of require with a SYNCHRONOUS XmlHttpRequest:
Basically, what require thus does, is it downloads a JavaScript-file, evals it in an anonymous namespace (aka Function), with the parameters "require", "exports" and "module", and returns the exports, meaning an object's public functions and properties.
Note that this evaluation is recursive: you require files, which themselfs can require files.
This way, all "global" variables used in your module are variables in the require-wrapper-function namespace, and don't pollute the global scope with unwanted variables.
Also, this way, you can reuse code without depending on namespaces, so you get "modularity" in JavaScript. "modularity" in quotes, because this is not exactly true, though, because you can still write window.bla/global.bla, and hence still pollute the global scope... Also, this establishes a separation between private and public functions, the public functions being the exports.
Now instead of saying
You can also say:
and return an object.
Also, because your modules get evaluated in a function with parameters "require", "exports" and "module", your modules can use the undeclared variables "require", "exports" and "module", which might be startling at first. The require parameter there is of course a pointer to the require function saved into a variable.
Cool, right ?
Seen this way, require looses its magic, and becomes simple.
Now, the real require-function will do a few more checks and quirks, of course, but this is the essence of what that boils down to.
Also, in 2020, you should use the ECMA implementations instead of require:
And if you need a dynamic non-static import (e.g. load a polyfill based on browser-type), there is the ECMA-import function/keyword:
note that import is not synchronous like require.
Instead, import is a promise, so
becomes
because import returns a promise (asynchronous).
So basically, unlike require, import replaces fs.readFileSync with fs.readFileAsync.
This of course requires the import-function to be async as well.
Even better, right ?
Well yea, except that there is no ECMA-way to dynamically import synchronously (without promise).
Now, to understand the repercussions, you absolutely might want to read up on promises/async-await here , if you don't know what that is.
But very simply put, if a function returns a promise, it can be "awaited":
The promise would then normally be used like this:
But when you return a promise, you can also use await, which means we get rid of the callback (sort of - actually, it is being replaced with a state-machine in the compiler/interpreter).
This way, we make asynchronous code feel like synchronous, so we now can use try-catch for error-handling.
Note that if you want to use await in a function, that function must be declared async (hence async-await).
And also please note that in JavaScript, there is no way to call an async function (blockingly) from a synchronous one (the ones you know). So if you want to use await (aka ECMA-import), all your code needs to be async, which most likely is a problem, if everything isn't already async...
An example of where this simplified implementation of require fails, is when you require a file that is not valid JavaScript, e.g. when you require css, html, txt, svg and images or other binary files.
And it's easy to see why:
If you e.g. put HTML into a JavaScript function body, you of course rightfully get
because of
Function("bla", "<doctype...")
Now, if you wanted to extend this to for example include non-modules, you could just check the downloaded file-contents for
code.indexOf("module.exports") == -1
, and then e.g. eval("jquery content") instead of Func (which works fine as long as you're in the browser). Since downloads with Fetch/XmlHttpRequests are subject to the same-origin-policy, and integrity is ensured by SSL/TLS, the use of eval here is rather harmless, provided you checked the JS files before you added them to your site, but that much should be standard-operating-procedure.Note that there are several implementations of require-like functionality:
Important sidenote on the function argument "exports":
JavaScript uses call-by-value-sharing - meaning objects are passed as a pointer, but the pointer-value itselfs is passed BY VALUE, not by reference. So you can't override exports by assigning it a new object. Instead, if you want to override exports, you need to assign the new object to module.exports - because hey, module is the pointer passed by value, but exports in module.exports is the reference to the original exports pointer.
Important sidenote on module-Scope:
Modules are evaluated ONCE, and then cached by require.
That means all your modules have a Singleton scope.
If you want a non-singleton scope, you have to do something like:
or simply
with appropriate code returned by your module.