Co To jest Javascript "require"?

Próbuję zmusić Javascript do odczytu/zapisu do bazy danych PostgreSQL. Znalazłem ten Projekt na GitHubie. Udało mi się uzyskać następujący przykładowy kod do uruchomienia w węźle.

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

Następnie próbowałem uruchomić go na stronie internetowej, ale wydawało się, że nic się nie dzieje. Sprawdziłem na konsoli Javascript i po prostu mówi " require not defined."

Więc co to jest " wymagać?"Dlaczego działa w node, a nie na stronie internetowej?

Również, zanim dostałem go do pracy w node, I musiałem zrobić npm install pg. O co chodzi? Zajrzałem do katalogu i nie znalazłem pliku. Gdzie go umieścił i jak Znajduje go Javascript?

Author: neuromancer, 2012-03-28

7 answers

Więc co to jest "wymagać?"

require() nie jest częścią standardowego API JavaScript. Ale w węźle.js, jest to wbudowana funkcja o specjalnym przeznaczeniu: do ładowania modułów .

Moduły są sposobem na podzielenie aplikacji na osobne pliki, zamiast mieć wszystkie aplikacje w jednym pliku. Pojęcie to jest również obecne w innych językach z niewielkimi różnicami w składni i zachowaniu, jak C include, Python import, a więc on

Jedna duża różnica między węzłem.Moduły js i przeglądarka JavaScript to sposób, w jaki kod jednego skryptu jest dostępny z kodu innego skryptu.

  • W przeglądarce JavaScript skrypty są dodawane za pomocą elementu <script>. Kiedy wykonują, wszystkie mają bezpośredni dostęp do globalnego zakresu, "wspólnej przestrzeni" między wszystkimi skryptami. Każdy skrypt może dowolnie definiować/modyfikować/usuwać / wywoływać cokolwiek w globalnym zasięgu.

  • W Węźle.js, każdy moduł ma swój własny zakres. Moduł nie może bezpośrednio uzyskać dostępu do rzeczy zdefiniowanych w innym module, chyba że zdecyduje się je ujawnić. Aby wyeksponować rzeczy z modułu, muszą być przypisane do exports lub module.exports. Aby moduł miał dostęp do innego modułu exports lub module.exports, musi używać require().

W Twoim kodzie, var pg = require('pg'); ładuje pg moduł, klient PostgreSQL dla Node.js. Pozwala to kodowi uzyskać dostęp do funkcji API klienta PostgreSQL za pomocą zmiennej pg.

Dlaczego działa w node, ale nie na stronie internetowej?

require(), module.exports i exports są API systemu modułów specyficznych dla węzła.js. Przeglądarki nie implementują tego systemu modułów.

Również, zanim dostałem go do pracy w node, musiałem zrobić npm install pg. O co chodzi?

NPM {[26] } to usługa repozytorium pakietów, która obsługuje opublikowane Moduły JavaScript. npm install to polecenie, które umożliwia pobieranie pakietów z ich repozytorium.

Gdzie go umieścił i jak Javascript go znalazł?

Npm CLI umieszcza wszystkie pobrane Moduły w node_modules katalogu, w którym uruchomiłeś npm install. Węzeł.js posiada bardzo szczegółową dokumentację jak moduły znajdują inne moduły , która obejmuje znalezienie katalogu node_modules.

 961
Author: Joseph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-15 12:07:40

W porządku, zacznijmy więc od rozróżnienia między Javascript w przeglądarce internetowej, a Javascript na serwerze (CommonJS i Node).

Javascript jest językiem tradycyjnie ograniczonym do przeglądarki internetowej z ograniczonym globalnym kontekstem zdefiniowanym głównie przez coś, co stało się znane jako Document Object Model (DOM) level 0 (API Javascript Netscape Navigator).

Po stronie serwera Javascript eliminuje to ograniczenie i pozwala Javascript na wywołanie różne fragmenty kodu natywnego (jak biblioteka Postgres) i otwarte gniazda.

Now require() jest specjalnym wywołaniem funkcji zdefiniowanym jako część specyfikacji CommonJS. W node rozwiązuje biblioteki i moduły w ścieżce wyszukiwania węzła, obecnie Zwykle zdefiniowanej jako node_modules w tym samym katalogu (lub katalogu wywołanego pliku javascript) lub w ścieżce wyszukiwania dla całego systemu.

Aby spróbować odpowiedzieć na resztę pytania, musimy użyć proxy między kodem uruchomionym w przeglądarce i serwer bazy danych.

Ponieważ omawiamy węzeł i jesteś już zaznajomiony z tym, jak uruchomić zapytanie z tego miejsca, sensowne byłoby użycie node jako tego proxy.

Jako prosty przykład stworzymy adres URL, który zwróci kilka faktów o Beatlesie, o nazwie, jako 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');
 113
Author: Timothy Meade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 09:34:26

Zauważyłem, że podczas gdy inne odpowiedzi wyjaśniały, co to jest wymaganie i że służy do ładowania modułów w węźle, nie dały pełnej odpowiedzi na temat ładowania modułów węzła podczas pracy w przeglądarce.

Jest to dość proste do zrobienia. Zainstaluj swój moduł używając npm, jak to opisałeś, a sam moduł będzie znajdować się w folderze Zwykle nazywanym node_modules.

Teraz najprostszym sposobem na załadowanie go do aplikacji jest odwołanie się do niego z html za pomocą znacznika skryptu, który wskazuje na ten katalog. jeśli twój katalog node_modules znajduje się w katalogu głównym projektu na tym samym poziomie co twój indeks.html napiszesz to w swoim indeksie.html:

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

Cały skrypt zostanie teraz załadowany do strony - dzięki czemu można uzyskać bezpośredni dostęp do jego zmiennych i metod.

Istnieją inne podejścia, które są szerzej stosowane w większych projektach, takie jak moduł Ładowarki jak wymagają.js . Z tych dwóch, nie używałem wymagają siebie, ale myślę, że jest to uważane przez wielu ludzi jest na dobrej drodze.

 30
Author: Sam Redway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-22 21:57:24

Służy do ładowania modułów. Użyjmy prostego przykładu.

W pliku 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;
    }
}

Możemy użyć tego poprzez require, Jak:

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

Metoda require() służy do ładowania i buforowania modułów JavaScript. Tak więc, jeśli chcesz załadować lokalny, względny moduł JavaScript do węzła.aplikacji js, można po prostu użyć metody require().

Przykład:

var yourModule = require( "your_module_name" ); //.js file extension is optional
 30
Author: Sudhir Bastakoti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 09:40:56

Wiesz, jak uruchamiając JavaScript w przeglądarce, masz dostęp do zmiennych takich jak "okno" lub Matematyka? Nie musisz deklarować tych zmiennych, zostały one napisane do użycia, kiedy tylko chcesz.

Cóż, gdy uruchamiasz plik w węźle.środowiska js, istnieje zmienna, której możesz użyć. Nazywa się "moduł" jest to obiekt. Posiada nieruchomość o nazwie "exports."I działa tak:

W pliku, który nazwiemy example.js, ty napisz:

Przykład.js

module.exports = "some code";

Teraz, chcesz ten ciąg "jakiś kod" w innym pliku.

Nazwiemy inny plik otherFile.js

W tym pliku piszesz:

OtherFile.js

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

Instrukcja require() trafia do pliku, który umieścisz w nim i odnajduje dane przechowywane w module.eksport nieruchomości. Let str = ... część kodu oznacza, że to, co wymaga zwrócenia instrukcji, jest przechowywane w str zmienna.

Tak więc w tym przykładzie wynikiem końcowym jest to, że w otherFile.js masz teraz to:

Let string = "jakiś kod";

  • lub -

Let str = ('./ przykładjs").moduł.eksport

Uwaga:

Nazwa pliku zapisana wewnątrz instrukcji require: jeśli jest to plik lokalny, powinna to być ścieżka do przykładu.js. A także ... rozszerzenie js jest dodawane domyślnie, więc nie musiałem go pisać.

Robisz coś podobnego gdy wymaga węzła.biblioteki js, takie jak Express. W ekspresie.plik js, istnieje obiekt o nazwie 'module' , z właściwością o nazwie 'exports'.

Więc, wygląda to coś w tym stylu, pod maską (jestem trochę początkujący, więc niektóre z tych szczegółów mogą nie być dokładne, ale to po to, aby pokazać koncepcję: {]}

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){}){}
     }
}

Jeśli potrzebujesz modułu, wygląda to tak: const moduleName = require ("Nazwa modułu");

Jeśli potrzebujesz lokalnego plik, wygląda tak: const localFile = require("./path/to / local-file");

(zwróć uwagę na ./ na początku nazwy pliku)


Zauważ również, że domyślnie eksport jest obiektem .. moduł np.exports = {} więc możesz napisać moduł.eksport.mojafunction = () = > {} przed przypisaniem wartości do modułu.eksport. Ale można również zastąpić obiekt przez moduł zapisu.exports = " nie jestem już obiektem."

 17
Author: Maiya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-11 16:24:51

Nekromancja.
IMHO, istniejące odpowiedzi pozostawiają wiele do życzenia.

To bardzo proste:
Require jest po prostu (niestandardową) funkcją zdefiniowaną w globalnym zasięgu .
(window in browser, global in NodeJS ).

Teraz, jako takie, aby odpowiedzieć na pytanie "co jest wymagane", "po prostu" musimy wiedzieć, co ta funkcja robi.
Najlepiej to wyjaśnić kodem.

Oto prosta implementacja autorstwa Michele Nasti , kod można znaleźć na jego stronie github .

Zasadniczo, nazwijmy naszą funkcję 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);

Teraz Można zauważyć, obiekt " fs " jest używany tutaj.
Dla uproszczenia, Michele właśnie zaimportował moduł NodeJS fs:

const fs = require('fs');
Co nie byłoby konieczne.
W przeglądarce można więc wykonać prostą implementację require z synchronicznym XmlHttpRequest:
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 
    }
};

Zasadniczo to, co wymaga, to pobierz plik JavaScript, ewaluj go w anonimowej przestrzeni nazw (Aka Function), z globalnymi parametrami "require", "exports" i "module", i zwróć eksport, co oznacza publiczne funkcje i właściwości obiektu.

Zauważ, że ta ocena jest rekurencyjna: wymagasz plików, które same w sobie mogą wymagać plików.

W ten sposób wszystkie" globalne " zmienne używane w module są zmiennymi w przestrzeni nazw require-wrapper-function i nie zanieczyszczają globalnego zakresu niechcianymi zmienne.

W ten sposób możesz również ponownie użyć kodu bez zależności od przestrzeni nazw, dzięki czemu uzyskasz "modułowość" w JavaScript. "modułowość" w cudzysłowach, ponieważ nie jest to jednak do końca prawda, ponieważ nadal można pisać okno.bla, a zatem nadal zanieczyszczają globalny zasięg...[53]} ustanawia to również rozdział między funkcjami prywatnymi i publicznymi, przy czym funkcje publiczne są eksportem.

Teraz zamiast mówić

module.exports = function(){ return 5*3;};
Możesz też powiedzieć:
function privateSomething()
{
    return 42:
}


function privateSomething2()
{
    return 21:
}


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

I zwraca obiekt.

Również dlatego, że Twoje moduły są oceniane w funkcji z parametrami "require", "exports" i "module", Twoje moduły mogą używać nierejestrowanych zmiennych "require", "exports" i "module", co może być zaskakujące na początku. Parametr require jest oczywiście wskaźnikiem ByVal do funkcji require zapisanym do zmiennej.
Fajnie, prawda ?
Widziany w ten sposób, wymaga traci swoją magię i staje się prosty.
Teraz prawdziwa funkcja require zrobi kilka oczywiście więcej kontroli i dziwactw, ale to jest istota tego, do czego się sprowadza.

W 2020 r. powinieneś używać implementacji ECMA zamiast 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";
Jeśli potrzebujesz dynamicznego, niestatycznego importu (np. załaduj polyfill na podstawie typu przeglądarki), istnieje funkcja / słowo kluczowe ECMA-import:
var promise = import("module-name");

Zauważ, że import nie jest synchroniczny jak require.
Zamiast tego import jest obietnicą, więc

var something = require("something");

Staje się

var something = await import("something");

Ponieważ import zwraca obietnicę (asynchroniczną).

Więc zasadniczo, w przeciwieństwie do require, import zastępuje fs.readFileSync z 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

To oczywiście wymaga asynchronicznej funkcji importu.

"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);
};
Nawet lepiej, prawda ?
No tak, tyle że nie ma ECMA-sposobu na dynamiczny import synchronicznie (bez obietnicy).

Teraz, aby zrozumieć reperkusje, absolutnie możesz chcieć przeczytać obietnice / async-czekaj tutaj , jeśli nie wiesz, co to jest.

Ale bardzo prosto mówiąc, jeśli funkcja zwraca obietnicę, może być "oczekiwana":

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)

Co jest dobrym sposobem, aby Kod asynchroniczny wyglądał synchronicznie.
Zauważ, że jeśli chcesz użyć asynchronicznego oczekiwania w funkcji, Ta funkcja musi być zadeklarowana jako asynchroniczna.

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

Należy również pamiętać, że w JavaScript nie ma sposobu na wywołanie funkcji asynchronicznej (blokowo) z synchronicznej (tej, którą znasz). Więc jeśli chcesz użyć wait (aka ECMA-import), cały kod musi być asynchroniczny, co najprawdopodobniej jest problemem, jeśli wszystko nie jest już asynchroniczne...

Przykładem tego, gdzie ta uproszczona implementacja require nie powiedzie się, jest to, gdy potrzebujesz pliku, który nie jest prawidłowym JavaScript, np. gdy potrzebujesz css, html, txt, svg i obrazów lub innych plików binarnych.
I łatwo zrozumieć dlaczego:
Jeśli np. umieścisz HTML w ciele funkcji JavaScript, oczywiście słusznie otrzymasz

SyntaxError: Unexpected token '<'

Ponieważ Function("bla", "<doctype...")

Teraz, jeśli chcesz rozszerzyć to na przykład include non-modules, możesz po prostu sprawdzić pobraną zawartość pliku za pomocą for code.indexOf("module.exports") == -1, a następnie np. eval ("zawartość jquery") zamiast Func (który działa dobrze, dopóki jesteś w przeglądarce). Ponieważ pobieranie z Fetch/XmlHttpRequests podlega tej samej polityce pochodzenia, a integralność jest zapewniona przez SSL / TLS, użycie eval tutaj jest raczej nieszkodliwe, pod warunkiem, że sprawdziłeś Pliki JS przed dodaniem ich do witryny, ale to powinna być standardowa procedura operacyjna.

Zauważ, że istnieje kilka implementacji funkcji podobnych do wymagań:

  • Format CommonJS (CJS) , używany w Node.js, wykorzystuje funkcję require i moduł.eksportuje w celu zdefiniowania zależności i modułów. Ekosystem npm jest zbudowany na tym formacie. (to jest to, co jest zaimplementowane powyżej)
  • format Asynchronous Module Definition (AMD) , używany w przeglądarkach, używa funkcji define do zdefiniuj Moduły.
  • format modułu ES (ESM) . Od wersji ES6 (ES2015) JavaScript obsługuje natywny format modułów. Używa słowa kluczowego export, aby wyeksportować publiczny API modułu i słowa kluczowego import, aby go zaimportować.
  • System.format rejestru , przeznaczony do obsługi modułów ES6 w ramach ES5.
  • Format Universal Module Definition (UMD) , kompatybilny ze wszystkimi wyżej wymienionymi formatami, używany zarówno w przeglądarce, jak i w węźle.js. On szczególnie przydatne, jeśli piszesz moduły, które mogą być używane zarówno w NodeJS, jak i w przeglądarce.
 8
Author: Stefan Steiger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-07 10:49:27

Dwa smaki modułu.export / require:

(Zobacz tutaj )

Smak 1
export file (różn."js"): {]}

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

Inny plik:

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

Flavour 2
export file (user."js"): {]}

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

Inny plik:

var user = require('./user');
var u = new user();
 7
Author: mike rodent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-02 14:33:36