这个Javascript"需要"是什么?

neu*_*cer 455 javascript database postgresql node.js

我正在尝试使用Javascript来读取/写入PostgreSQL数据库.我在github上找到了这个项目.我能够获得以下示例代码以在节点中运行.

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();
});
Run Code Online (Sandbox Code Playgroud)

接下来我尝试让它在网页上运行,但似乎没有任何事情发生.我查看了Javascript控制台,它只是说"require not defined."

那么"需要什么?" 为什么它在节点中工作而在网页中不起作用?

此外,在我开始在节点中工作之前,我必须这样做npm install pg.那是什么意思?我查看了目录,但没找到文件pg.它把它放在哪里,Javascript如何找到它?

Jos*_*eph 793

那么"需要什么?"

require()不属于标准JavaScript API.但是在Node.js中,它是一个具有特殊用途的内置函数:加载模块.

模块是一种将应用程序拆分为单独文件的方法,而不是将所有应用程序都放在一个文件中.这个概念也存在于其他语言中,在语法和行为方面存在细微差别,如C include,PHP import,Python <script>等.

Node.js模块和浏览器JavaScript之间的一个重要区别是如何从另一个脚本的代码访问一个脚本的代码.

  • 在浏览器JavaScript中,脚本通过exports元素添加.当它们执行时,它们都可以直接访问全局范围,即所有脚本中的"共享空间".任何脚本都可以在全局范围内自由定义/修改/删除/调用任何内容.

  • 在Node.js中,每个模块都有自己的范围.模块不能直接访问另一个模块中定义的内容,除非它选择公开它们.要从模块中公开事物,必须将它们分配给module.exportsexports.对于一个模块访问另一个模块module.exports或者require(),它必须使用var pg = require('pg');.

在您的代码中,pg加载pg模块,Node.js的PostgreSQL客户端.这允许您的代码通过require()变量访问PostgreSQL客户端API的功能.

为什么它在节点中工作而在网页中不起作用?

module.exports,exportsnpm install pg是一个模块系统特定于Node.js的的API的 浏览器不实现此模块系统.

另外,在我让它在节点中工作之前,我不得不做npm install pg.那是什么意思?

NPM是一个包存储JavaScript模块的包存储库服务.npm install是一个允许您从其存储库下载包的命令.

它把它放在哪里,Javascript如何找到它?

Node.js有关于模块如何查找其他模块的非常详细的文档.但是在一个要点中,它将所有下载的模块放在node_modules您运行的目录中npm install.

  • @Melab因为一旦代码膨胀到比大学编码练习更大的东西并且开始涉及超过1个人,就需要模块化.这是[为什么我们一直在使用它们,就像,永远](https://en.wikipedia.org/wiki/Mesa_(programming_language)). (17认同)
  • 我认为[WebPack也有自己的`require`支持](https://webpack.github.io/docs/context.html)? (11认同)
  • 为什么Node.js需要此功能? (2认同)
  • PHP中的等效项是`include / require [_once]`([php.net link](https://www.php.net/manual/zh/function/include.php)),而不是`use`,是[aliasing](https://www.php.net/manual/zh/language.namespaces.importing.php)关键字。 (2认同)
  • @juancarlospeñacabrera require 只返回 module.exports 在其文件中定义的内容。在您指出的情况下, require('socket.io') 返回一个函数,而 require('socket.io')(http) 将返回通过传递 http 参数调用该函数的结果,这将被分配给io:) (2认同)

Tim*_*ade 101

好吧,让我们首先开始区分Web浏览器中的 Javascript和服务器上的 Javascript (CommonJS和Node).

Javascript是一种传统上局限于Web浏览器的语言,其具有有限的全局上下文,主要由所谓的文档对象模型(DOM)级别0(Netscape Navigator Javascript API)定义.

服务器端Javascript消除了这种限制,允许Javascript调用各种本机代码(如Postgres库)和打开套接字.

现在require()是一个特殊的函数调用,定义为CommonJS规范的一部分.在节点中,它解析节点搜索路径中的库和模块,现在通常定义node_modules在同一目录(或调用的javascript文件的目录)或系统范围的搜索路径中.

为了尝试回答您的其余问题,我们需要在浏览器中运行的代码和数据库服务器之间使用代理.

由于我们正在讨论Node,并且您已经熟悉如何从那里运行查询,因此将Node用作该代理是有意义的.

作为一个简单的例子,我们将创建一个URL,该URL返回一些关于披头士的事实,给定一个名称,作为JSON.

/* your connection code */

var express = require('express');
var app = express.createServer();
app.get('/beatles/:name', function(req, res) {
    var name = req.params.name || '';
    name = name.replace(/[^a-zA_Z]/, '');
    if (!name.length) {
        res.send({});
    } else {
        var query = client.query('SELECT * FROM BEATLES WHERE name =\''+name+'\' LIMIT 1');
        var data = {};
        query.on('row', function(row) {
            data = row;
            res.send(data);
        });
    };
});
app.listen(80, '127.0.0.1');
Run Code Online (Sandbox Code Playgroud)

  • 它的混乱...方法`createServer`是混乱...它表明,我可以只威利迪丽创建服务器的时候,每当我想......相比之下,与我的WAMP的范例:大约5年前,我安装(如.'创建')我的windowsXP笔记本电脑上的服务器,我从来没有"创建"另一台服务器,因为......现在突然间我可以开始创建服务器...这让人感到困惑...... (2认同)
  • Express 是中间件和框架的集合,可以更轻松地在 Node.js 中创建 Web 服务器,您需要使用“npm”安装它。您可以在这里找到更多信息:http://expressjs.com/ (2认同)

Sud*_*oti 27

它用于加载模块.让我们用一个简单的例子.

在档案中circle_object.js:

var Circle = function (radius) {
    this.radius = radius
}
Circle.PI = 3.14

Circle.prototype = {
    area: function () {
        return Circle.PI * this.radius * this.radius;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们可以使用这个require,例如:

node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
Run Code Online (Sandbox Code Playgroud)

require()方法用于加载和缓存JavaScript模块.因此,如果要将本地相对JavaScript模块加载到Node.js应用程序中,只需使用该require()方法即可.

例:

var yourModule = require( "your_module_name" ); //.js file extension is optional
Run Code Online (Sandbox Code Playgroud)

  • 如果您尝试在网页中使用该怎么办? (8认同)
  • 第一个代码块是否应该位于名为circle_object.js的文件中? (7认同)
  • 我正在尝试将上述内容加载到网页中! (2认同)

Sam*_*way 20

我注意到,虽然其他答案解释了需求是什么,并且它用于在Node中加载模块,但他们没有给出在浏览器中工作时如何加载节点模块的完整答复.

这很简单.如您所述,使用npm安装模块,模块本身将位于通常称为node_modules的文件夹中.

现在,将它加载到您的应用程序的最简单方法是从您的html引用它,并带有指向此目录的脚本标记.即如果您的node_modules目录位于与index.html相同级别的项目根目录中,您可以在index.html中编写:

<script src="node_modules/ng"></script>
Run Code Online (Sandbox Code Playgroud)

整个脚本现在将加载到页面中 - 因此您可以直接访问其变量和方法.

在大型项目中还有其他更广泛使用的方法,例如像require.js这样的模块加载器.在这两个中,我没有使用过自己的需求,但我认为很多人都认为这是可行的.


Ste*_*ger 13

死灵法术。
恕我直言,现有的答案还有很多不足之处。

这很简单:
Require 只是一个在全局范围内定义的(非标准)函数。
(浏览器中的窗口,NodeJS 中的全局窗口)。

现在,为了回答“需要什么”这个问题,我们“简单地”需要知道这个函数的作用。
这也许最好用代码来解释。

这是Michele Nasti的一个简单实现,您可以在他的 github 页面上找到代码。

基本上,让我们调用我们的minimalisc require 函数myRequire:

function myRequire(name) 
{
    console.log(`Evaluating file ${name}`);
    if (!(name in myRequire.cache)) {
        console.log(`${name} is not in cache; reading from disk`);
        let code = fs.readFileSync(name, 'utf8');
        let module = { exports: {} };
        myRequire.cache[name] = module;
        let wrapper = Function("require, exports, module", code);
        wrapper(myRequire, module.exports, module);
    }
    console.log(`${name} is in cache. Returning it...`);
    return myRequire.cache[name].exports;
}
myRequire.cache = Object.create(null);
window.require = myRequire;
const stuff = window.require('./main.js');
console.log(stuff);
Run Code Online (Sandbox Code Playgroud)

现在您注意到,这里使用了对象“fs”。
为简单起见,Michele 只导入了 NodeJS fs 模块:

const fs = require('fs');
Run Code Online (Sandbox Code Playgroud)

这没有必要。
因此,在浏览器中,您可以使用 SYNCHRONOUS XmlHttpRequest 对 require 进行简单的实现:

const fs = {
    file: `
    // module.exports = \"Hello World\";
        
    module.exports = function(){ return 5*3;};
    
    `
    , getFile(fileName: string, encoding: string): string
    {
        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
        let client = new XMLHttpRequest();
        // client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");

        // open(method, url, async)
        client.open("GET", fileName, false);
        client.send();
        if (client.status === 200)
            return client.responseText;

        return null;
    }


    , readFileSync: function (fileName: string, encoding: string): string
    {
        // this.getFile(fileName, encoding);
        return this.file; // Example, getFile would fetch this file 
    }
};
Run Code Online (Sandbox Code Playgroud)

基本上,require 所做的是下载一个 JavaScript 文件,在匿名命名空间(又名函数)中对其进行评估,使用全局参数“require”、“exports”和“module”,然后返回导出,这意味着对象的公共功能和属性。

请注意,此评估是递归的:您需要文件,而文件本身可以需要文件。

这样,模块中使用的所有“全局”变量都是 require-wrapper-function 命名空间中的变量,并且不会用不需要的变量污染全局范围。

此外,通过这种方式,您可以在不依赖名称空间的情况下重用代码,从而在 JavaScript 中获得“模块化”。引号中的“模块化”,因为这并不完全正确,因为您仍然可以编写 window.bla,因此仍然会污染全局范围......此外,这在私有函数和公共函数之间建立了分离,公共函数是出口。

现在而不是说

module.exports = function(){ return 5*3;};
Run Code Online (Sandbox Code Playgroud)

你也可以说:

function privateSomething()
{
    return 42:
}


function privateSomething2()
{
    return 21:
}


module.exports = {
      getRandomNumber: privateSomething
     ,getHalfRandomNumber: privateSomething2
};
Run Code Online (Sandbox Code Playgroud)

并返回一个对象。

此外,由于您的模块在带有参数“require”、“exports”和“module”的函数中进行评估,因此您的模块可以使用未声明的变量“require”、“exports”和“module”,这起初可能会令人吃惊。这里的 require 参数当然是一个 ByVal 指针,指向保存到变量中的 require 函数。
酷,对吧?
这样看来, require 失去了它的魔力,变得简单了。
现在,真正的 require 函数当然会做更多的检查和怪癖,但这就是归结起来的本质。

此外,在 2020 年,您应该使用 ECMA 实现而不是 require:

import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
Run Code Online (Sandbox Code Playgroud)

如果您需要动态非静态导入(例如根据浏览器类型加载 polyfill),则可以使用 ECMA-import 函数/关键字:

var promise = import("module-name");
Run Code Online (Sandbox Code Playgroud)

请注意,导入不像需要那样同步。
相反,导入是一个承诺,所以

var something = require("something");
Run Code Online (Sandbox Code Playgroud)

变成

var something = await import("something");
Run Code Online (Sandbox Code Playgroud)

因为 import 返回一个承诺(异步)。

所以基本上,与 require 不同,import 用 fs.readFileAsync 替换了 fs.readFileSync。

async readFileAsync(fileName, encoding) 
{
    const textDecoder = new TextDecoder(encoding);
    // textDecoder.ignoreBOM = true;
    const response = await fetch(fileName);
    console.log(response.ok);
    console.log(response.status);
    console.log(response.statusText);
    // let json = await response.json();
    // let txt = await response.text();
    // let blo:Blob = response.blob();
    // let ab:ArrayBuffer = await response.arrayBuffer();
    // let fd = await response.formData()
    // Read file almost by line
    // https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#Example_2_-_handling_text_line_by_line
    let buffer = await response.arrayBuffer();
    let file = textDecoder.decode(buffer);
    return file;
} // End Function readFileAsync
Run Code Online (Sandbox Code Playgroud)

这当然也需要导入函数是异步的

"use strict";
async function myRequireAsync(name) {
    console.log(`Evaluating file ${name}`);
    if (!(name in myRequireAsync.cache)) {
        console.log(`${name} is not in cache; reading from disk`);
        let code = await fs.readFileAsync(name, 'utf8');
        let module = { exports: {} };
        myRequireAsync.cache[name] = module;
        let wrapper = Function("asyncRequire, exports, module", code);
        await wrapper(myRequireAsync, module.exports, module);
    }
    console.log(`${name} is in cache. Returning it...`);
    return myRequireAsync.cache[name].exports;
}
myRequireAsync.cache = Object.create(null);
window.asyncRequire = myRequireAsync;
async () => {
    const asyncStuff = await window.asyncRequire('./main.js');
    console.log(asyncStuff);
};
Run Code Online (Sandbox Code Playgroud)

更好,对吧?
嗯,是的,除了没有 ECMA 方式来同步动态导入(没有承诺)。

现在,要了解影响,如果您不知道那是什么,您绝对可能想在这里阅读 promises/async-await

但非常简单地说,如果一个函数返回一个承诺,它可以被“等待”:

function sleep (fn, par) 
{
  return new Promise((resolve) => {
    // wait 3s before calling fn(par)
    setTimeout(() => resolve(fn(par)), 3000)
  })
}


var fileList = await sleep(listFiles, nextPageToken)
Run Code Online (Sandbox Code Playgroud)

这是使异步代码看起来同步的好方法。
请注意,如果要在函数中使用 async await,则该函数必须声明为 async。

async function doSomethingAsync()
{
    var fileList = await sleep(listFiles, nextPageToken)
}
Run Code Online (Sandbox Code Playgroud)

还请注意,在 JavaScript 中,无法从同步函数(您知道的函数)调用异步函数(阻塞式)。因此,如果您想使用 await(又名 ECMA 导入),您的所有代码都需要是异步的,这很可能是一个问题,如果一切还不是异步的...

这种简化的 require 实现失败的一个例子是,当您需要一个无效的 JavaScript 文件时,例如,当您需要 css、html、txt、svg 和图像或其他二进制文件时。
并且很容易理解为什么:
如果你将 HTML 放入 JavaScript 函数体中,你当然会得到

SyntaxError: Unexpected token '<'
Run Code Online (Sandbox Code Playgroud)

因为 Function("bla", "<doctype...")

现在,如果您想将其扩展为例如包含非模块,您可以只检查下载的文件内容 for code.indexOf("module.exports") == -1,然后例如 eval("jquery content") 而不是 Func (只要您就可以正常工作)重新在浏览器中)。由于使用 Fetch/XmlHttpRequests 的下载受同源策略的约束,并且完整性由 SSL/TLS 确保,因此在此处使用 eval 是无害的,前提是您在将 JS 文件添加到您的站点之前检查了它们,但是大部分应该是标准操作程序。

请注意,有多种类似 require 的功能的实现:

  • Node.js 中使用的 CommonJS (CJS) 格式使用 require 函数和 module.exports 来定义依赖项和模块。npm 生态系统建立在这种格式之上。(这是上面实现的)
  • 浏览器中使用的异步模块定义 (AMD) 格式使用定义函数来定义模块。
  • ES 模块 (ESM) 格式。从 ES6 (ES2015) 开始,JavaScript 支持原生模块格式。它使用 export 关键字导出模块的公共 API,并使用 import 关键字导入它。
  • System.register 格式,旨在支持 ES5 中的 ES6 模块。
  • 通用模块定义 (UMD) 格式,兼容上述所有格式,可在浏览器和 Node.js 中使用。如果您编写可在 NodeJS 和浏览器中使用的模块,这将特别有用。


Mai*_*iya 10

您知道在浏览器中运行JavaScript时如何访问“窗口”或“数学”等变量吗?您不必声明这些变量,而是已编写它们供您随时使用。

好吧,当您在Node.js环境中运行文件时,可以使用一个变量。它称为“模块”。它是一个对象。它具有一个称为“出口”的属性。它是这样的:

在我们将其命名为example.js的文件中,您将编写:

example.js

module.exports = "some code";
Run Code Online (Sandbox Code Playgroud)

现在,您希望将此字符串“某些代码”存储在另一个文件中。

我们将另一个文件命名为otherFile.js

在此文件中,您编写:

otherFile.js

let str = require('example.js')
Run Code Online (Sandbox Code Playgroud)

该require()语句转到您放入其中的文件,查找存储在module.exports属性中的所有数据。代码的let str = ...部分意味着将require语句返回的任何内容存储到str变量中。

因此,在此示例中,最终结果是在otherFile.js中,您现在有了以下代码:

let string =“某些代码”;

  • 要么 -

让str =('./example.js').module.exports

注意:

在require语句中写入的文件名:如果是本地文件,则应为example.js的文件路径。另外,.js扩展名是默认添加的,因此我不必编写它。

当需要诸如Express的node.js库时,您可以执行类似的操作。在express.js文件中,有一个名为“模块”的对象,其对象名为“ exports”。

因此,它看起来像是沿着这些思路,在幕后(我是个初学者,所以其中一些细节可能并不准确,但这只是为了展示这个概念:

express.js

module.exports = function() {
    //It returns an object with all of the server methods
    return {
        listen: function(port){},
        get: function(route, function(req, res){}){}
     }
}
Run Code Online (Sandbox Code Playgroud)

如果需要模块,则如下所示:const moduleName = require(“ module-name”);

如果需要本地文件,则如下所示:const localFile = require(“ ./ local-file”);

(注意文件名开头的./)


另外请注意,默认情况下,导出是一个对象。例如,module.exports = {}因此,您可以在为module.exports赋值之前编写module.exports.myfunction =()=> {}。但是您也可以通过编写module.exports =“我不再是对象了”来替换该对象。


mik*_*ent 7

module.exports / require 的两种风格:

(见这里

风味 1
导出文件 (misc.js):

var x = 5;
var addX = function(value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
Run Code Online (Sandbox Code Playgroud)

其他文件:

var misc = require('./misc');
console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));
Run Code Online (Sandbox Code Playgroud)

风味 2
导出文件 (user.js):

var User = function(name, email) {
  this.name = name;
  this.email = email;
};
module.exports = User;
Run Code Online (Sandbox Code Playgroud)

其他文件:

var user = require('./user');
var u = new user();
Run Code Online (Sandbox Code Playgroud)