这个Javascript“要求”是什么?

2020/09/25 01:41 · javascript ·  · 0评论

我正在尝试获取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();
});

接下来,我试图使其在网页上运行,但是似乎什么也没有发生。我在Javascript控制台上进行了检查,它只显示“要求未定义”。

那么这是什么“要求”?为什么它在节点中有效但在网页中无效?

另外,在我让它在节点上工作之前,我必须做npm install pg那是什么意思 我查看了目录,但没有找到文件pg。它放在哪里,以及Javascript如何找到它?

那么这是什么“要求”?

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

模块是一种将应用程序拆分为单独文件的方法,而不是将所有应用程序都包含在一个文件中。其他语言在语法和行为上也存在细微差别,例如C include,Python import等等,也存在该概念

Node.js模块和浏览器JavaScript之间的最大区别在于,如何从另一个脚本的代码访问一个脚本的代码。

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

  • 在Node.js中,每个模块都有自己的作用域。一个模块不能直接访问另一个模块中定义的内容,除非它选择公开它们。要公开模块中的内容,必须将它们分配给exportsmodule.exports要使一个模块访问另一个模块的exportsmodule.exports必须使用require()

在您的代码中,var pg = require('pg');加载pg模块,即Node.js的PostgreSQL客户端。这使您的代码可以通过pg变量访问PostgreSQL客户端API的功能

为什么它在节点中有效但在网页中无效?

require()module.exportsexports是一个模块系统特定于Node.js的的API的 浏览器未实现此模块系统。

另外,在我让它在节点上工作之前,我必须做npm install pg那是什么意思

NPM是一个软件包存储库服务,用于承载已发布的JavaScript模块。npm install是一个命令,可让您从其存储库中下载软件包。

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

npm cli将所有下载的模块放在node_modules您运行目录中npm installNode.js拥有关于模块如何查找其他模块的非常详细的文档,包括查找node_modules目录。

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

Javascript通常是局限在Web浏览器中的一种语言,其全局上下文有限,而该上下文主要由后来称为文档对象模型(DOM)级别0(Netscape Navigator Javascript API)定义。

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

现在require()是定义为CommonJS规范一部分的特殊函数调用。在node中,它解析Node搜索路径中的库和模块,现在通常将其定义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');

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

在文件中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;
    }
}

我们可以通过来使用它require,例如:

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

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

例:

var yourModule = require( "your_module_name" ); //.js file extension is optional

我注意到,尽管其他答案解释了要求是什么,并且该答案用于在Node中加载模块,但它们并未对在浏览器中工作时如何加载节点模块给出完整的答复。

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

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

<script src="node_modules/ng"></script>

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

在大型项目中还有其他更广泛使用的方法,例如require.js之类的模块加载器在这两个中,我没有使用Require my,但是我认为许多人认为它是可行的方式。

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

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

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

example.js

module.exports = "some code";

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

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

在此文件中,您编写:

otherFile.js

let str = require('./example.js')

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

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

let string =“某些代码”;

  • 要么 -

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

注意:

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

当需要node.js库(例如Express)时,您可以执行类似的操作。在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){}){}
     }
}

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

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

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


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

两种形式的module.exports /要求:

(请参阅此处

风味1

导出文件(misc.js):

var x = 5;
var addX = function(value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

其他档案:

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

风味2

导出文件(user.js):

var User = function(name, email) {
  this.name = name;
  this.email = email;
};
module.exports = User;

其他档案:

var user = require('./user');
var u = new user();

死灵法师。

恕我直言,现有的答案有很多不足之处。

非常简单:

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);

现在您注意到,这里使用了对象“ fs”。

为了简单起见,Michele刚刚导入了NodeJS fs模块:

const fs = require('fs');

没必要的。

因此,在浏览器中,您可以使用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 
    }
};

因此,基本上,需求就是下载一个JavaScript文件,并将其评估为具有全局参数“ require”,“ exports”和“ module”的匿名命名空间(aka Function),然后返回导出,这意味着对象是公共的。功能和特性。

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

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

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

现在不用说

module.exports = function(){ return 5*3;};

您还可以说:

function privateSomething()
{
    return 42:
}


function privateSomething2()
{
    return 21:
}


module.exports = {
      getRandomNumber: privateSomething
     ,getHalfRandomNumber: privateSomething2
};

并返回一个对象。

另外,由于您的模块在具有参数“ require”,“ exports”和“ module”的函数中进行求值,因此您的模块可以使用未声明的变量“ require”,“ exports”和“ module”,这些变量一开始可能会令人吃惊。当然,require参数有一个ByVal指针,指向保存到变量中的require函数。

酷吧?


这样看来,要求放松其魔力,并变得简单。


现在,真正的需求功能将进行更多的检查和怪癖,但这是归根结底的本质。

另外,在2020年,您应该使用ECMA实施,而不是要求:

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";

并且,如果您需要动态非静态导入(例如,基于浏览器类型加载polyfill),则可以使用ECMA导入功能/关键字:

var promise = import("module-name");

请注意,导入不是像require那样同步。

相反,导入是一种承诺,因此

var something = require("something");

变成

var something = await import("something");

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

因此,基本上,与要求不同,导入将fs.readFileSync替换为fs.readFileAsync。

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

当然,这也要求import-function也要异步

"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);
};

更好吧?

是的,是的,除了没有ECMA方式可以动态地同步导入(无承诺)。

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

但简单地说,如果一个函数返回一个promise,则可以“等待”它:

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)

这是使异步代码看起来同步的好方法。

请注意,如果要在函数中使用异步等待,则必须将该函数声明为异步。

async function doSomethingAsync()
{
    var fileList = await sleep(listFiles, nextPageToken)
}

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

当您需要一个无效的JavaScript文件时,例如当您需要CSS,HTML,TXT,SVG和图像或其他二进制文件时,这种简化的require实施失败的例子。

而且很容易理解为什么:


如果将HTML放入JavaScript函数体中,那么您当然会正确地得到

SyntaxError: Unexpected token '<'

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

现在,如果您想将其扩展到例如包含非模块,则只需使用for检查下载的文件内容code.indexOf("module.exports") == -1,然后使用eval(“ jquery content”)代替Func(只要您可以,在浏览器中)。由于使用Fetch / XmlHttpRequests进行的下载遵循相同的原产地策略,并且SSL / TLS确保了完整性,因此,如果在将JS文件添加到站点之前已对其进行检查,则在此处使用eval不会造成任何危害。很多应该是标准操作程序。

请注意,有几种类似需求的功能的实现:

本文地址:http://javascript.askforanswer.com/zhegejavascriptyaoqiushishenme.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!