搜尋
首頁web前端js教程建立內容管理系統:nodePress

您已使用 Go 成功建立了平面檔案系統內容管理系統 (CMS)。下一步是採用同樣的理念,使用 Node.js 製作一個 Web 伺服器。我將向您展示如何載入庫、建立伺服器和運行伺服器。

此 CMS 將使用第一個教學課程「建立 CMS:結構和樣式」中介紹的網站資料結構。因此,請下載此基本結構並將其安裝在新目錄中。

取得節點和節點庫

在 Mac 上安裝 Node.js 最簡單的方法是使用 Homebrew。如果您尚未安裝 Homebrew,教學 Homebrew 揭秘:OS X 的終極套件管理器將向您展示如何安裝。

要使用 Homebrew 安裝 Node.js,請在終端機中輸入以下指令:

brew install node

完成後,您的 Mac 上將完全安裝了 Node 和 npm 命令。對於所有其他平台,請按照 Node.js 網站上的說明進行操作。

請注意:許多套件管理器目前正在安裝 Node.js 版本 0.10。本教學假設您擁有 5.3 或更高版本。您可以鍵入以下內容來檢查您的版本:

node --version

node 指令執行 JavaScript 解譯器。 npm 指令是 Node.js 的套件管理器,用於安裝新程式庫、建立新專案以及執行專案腳本。 Envato Tuts 上有許多關於 Node.js 和 NPM 的精彩教學和課程。

要安裝 Web 伺服器的庫,您必須在 Terminal.app 或 iTerm.app 程式中執行以下命令:

npm install express --save
npm install handlebars --save
npm install moment --save
npm install marked --save
npm install jade --save
npm install morgan --save

Express 是一個 Web 應用程式開發平台。它類似Go中的goWeb函式庫。 Handlebars 是用於建立頁面的模板引擎。 Moment 是一個用於處理日期的函式庫。 Marked 是一個很棒的 JavaScript 中 Markdown 到 HTML 轉換器。 Jade 是一種 HTML 速記語言,可輕鬆建立 HTML。 Morgan 是 Express 的中間件庫,可產生 Apache 標準日誌檔案。

安裝庫的另一種方法是下載本教學的來源檔案。下載並解壓縮後,在主目錄中輸入:

npm --install

這將安裝創建該專案所需的一切。

nodePress.js

現在您可以開始建立伺服器了。在專案的頂層目錄中,建立一個名為 nodePress.js 的文件,在您選擇的編輯器中開啟它,然後開始新增以下程式碼。我將解釋放入文件中的程式碼。

//
// Load the libraries used.
//
var fs = require('fs');
var path = require("path");
var child_process = require('child_process');
var process = require('process');
var express = require('express'); // http://expressjs.com/en/
var morgan = require('morgan'); // https://github.com/expressjs/morgan
var Handlebars = require("handlebars"); // http://handlebarsjs.com/
var moment = require("moment"); // http://momentjs.com/
var marked = require('marked'); // https://github.com/chjj/marked
var jade = require('jade'); // http://jade-lang.com/

伺服器程式碼從初始化用於建立伺服器的所有程式庫開始。沒有帶有網址的註解的函式庫是內部 Node.js 函式庫。

//
// Setup Global Variables.
//
var parts = JSON.parse(fs.readFileSync('./server.json', 'utf8'));
var styleDir = process.cwd() + '/themes/styling/' + parts['CurrentStyling'];
var layoutDir = process.cwd() + '/themes/layouts/' + parts['CurrentLayout'];
var siteCSS = null;
var siteScripts = null;
var mainPage = null;

接下來,我設定所有全域變數和庫配置。使用全域變數並不是最好的軟體設計實踐,但它確實有效並有助於快速開發。

parts 變數是一個包含網頁所有部分的雜湊數組。每個頁面都引用該變數的內容。它從伺服器目錄頂部的 server.json 檔案的內容開始。

然後,我使用 server.json 檔案中的資訊來建立用於此網站的 styleslayouts 目錄的完整路徑。

接著將三個變數設定為空值:siteCSSsiteScriptsmainPage。這些全域變數將包含所有 CSS、JavaScript 和主索引頁內容。這三個項目是任何 Web 伺服器上要求最多的項目。因此,將它們保留在記憶體中可以節省時間。如果 server.json 檔案中的 Cache 變數為 false,則每個請求都會重新讀取這些項目。

marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false
});

此程式碼區塊用於配置 Marked 庫以從 Markdown 產生 HTML。大多數情況下,我會打開表格和 smartLists 支援。

parts["layout"] = fs.readFileSync(layoutDir + '/template.html', 'utf8');
parts["404"] = fs.readFileSync(styleDir + '/404.html', 'utf8');
parts["footer"] = fs.readFileSync(styleDir + '/footer.html', 'utf8');
parts["header"] = fs.readFileSync(styleDir + '/header.html', 'utf8');
parts["sidebar"] = fs.readFileSync(styleDir + '/sidebar.html', 'utf8');

//
// Read in the page parts.
//
var partFiles = fs.readdirSync(parts['Sitebase'] + "parts/");
partFiles.forEach(function(ele, index, array) {
   parts[path.basename(ele, path.extname(ele))] = figurePage(parts['Sitebase'] + "parts/" + path.basename(ele, path.extname(ele)));
});

parts 變數進一步載入 styleslayout 目錄中的部分。 site 目錄內的 parts 目錄中的每個檔案也被載入到 parts 全域變數中。不含副檔名的檔案名稱是用來儲存檔案內容的名稱。這些名稱在 Handlebars 巨集中會擴展。

//
// Setup Handlebar's Helpers.
//

//
// HandleBars Helper:     save
//
// Description: 		This helper expects a
// 						"<name>" "<value>" where the name
// 						is saved with the value for future
// 						expansions. It also returns the
// 						value directly.
//
Handlebars.registerHelper("save", function(name, text) {
	//
	// Local Variables.
	//
	var newName = "", newText = "";

	//
	// See if the name and text is in the first argument
	// with a |. If so, extract them properly. Otherwise,
	// use the name and text arguments as given.
	//
	if(name.indexOf("|") > 0) {
		var parts = name.split("|");
		newName = parts[0];
		newText = parts[1];
	} else {
		newName = name;
		newText = text;
	}

	//
	// Register the new helper.
	//
   Handlebars.registerHelper(newName, function() {
      return newText;
   });

   //
   // Return the text.
   //
   return newText;
});

//
// HandleBars Helper: 	date
//
// Description: 		This helper returns the date
// 						based on the format given.
//
Handlebars.registerHelper("date", function(dFormat) {
   return moment().format(dFormat);
});

//
// HandleBars Helper: 	cdate
//
// Description: 		This helper returns the date given
//  					in to a format based on the format
//						given.
//
Handlebars.registerHelper("cdate", function(cTime, dFormat) {
   return moment(cTime).format(dFormat);
});

下一段程式碼定義了我定義的在 Web 伺服器中使用的 Handlebars 幫助程式:savedatecdate。儲存助手允許在頁面內建立變數。此版本支援 goPress 版本,其中參數的名稱和值一起以「|」分隔。您也可以使用兩個參數指定保存。例如:

{{save "name|Richard Guay"}}
{{save "newName" "Richard Guay"}}

Name is: {{name}}
newName is: {{newName}}

這將產生相同的結果。我更喜歡第二種方法,但 Go 中的 Handlebars 庫不允許使用多個參數。

datecdate 帮助程序格式化当前日期 (date) 或给定日期 (cdate)根据 moment.js 库格式化规则。 cdate 帮助程序期望渲染的日期是第一个参数并且具有 ISO 8601 格式。

//
// Create and configure the server.
//
var nodePress = express();

//
// Configure middleware.
//
nodePress.use(morgan('combined'))

现在,代码创建一个 Express 实例来配置实际的服务器引擎。 nodePress.use() 函数设置中间件软件。中间件是在每次调用服务器时提供服务的任何代码。在这里,我设置了 Morgan.js 库来创建正确的服务器日志输出。

//
// Define the routes.
//
nodePress.get('/', function(request, response) {
   setBasicHeader(response);
   if((parts["Cache"] == true) && (mainPage != null)) {
       response.send(mainPage);
   } else {
   	mainPage = page("main");
   	response.send(mainPage);
   }
});

nodePress.get('/favicon.ico', function(request, response) {
   var options = {
      root: parts['Sitebase'] + 'images/',
      dotfiles: 'deny',
      headers: {
         'x-timestamp': Date.now(),
         'x-sent': true
      }
   };
   response.set("Content-Type", "image/ico");
   setBasicHeader(response);
   response.sendFile('favicon.ico', options, function(err) {
      if (err) {
         console.log(err);
         response.status(err.status).end();
      } else {
         console.log('Favicon was sent:', 'favicon.ico');
      }
   });
});

nodePress.get('/stylesheets.css', function(request, response) {
   response.set("Content-Type", "text/css");
   setBasicHeader(response);
   response.type("css");
   if((parts["Cache"] == true) && (siteCSS != null)) {
   	response.send(siteCSS);
   } else {
   	siteCSS = fs.readFileSync(parts['Sitebase'] + 'css/final/final.css');
   	response.send(siteCSS);
   }
});

nodePress.get('/scripts.js', function(request, response) {
   response.set("Content-Type", "text/javascript");
   setBasicHeader(response);
   if((parts["Cache"] == true) && (siteScripts != null)) {
   	response.send(siteScripts);
   } else {
   	siteScripts = fs.readFileSync(parts['Sitebase'] + 'js/final/final.js', 'utf8');
   	response.send(siteScripts);
   }
});

nodePress.get('/images/:image', function(request, response) {
   var options = {
      root: parts['Sitebase'] + 'images/',
      dotfiles: 'deny',
      headers: {
         'x-timestamp': Date.now(),
         'x-sent': true
      }
   };
   response.set("Content-Type", "image/" + path.extname(request.params.image).substr(1));
   setBasicHeader(response);
   response.sendFile(request.params.image, options, function(err) {
      if (err) {
         console.log(err);
         response.status(err.status).end();
      } else {
         console.log('Image was sent:', request.params.image);
      }
   });
});

nodePress.get('/posts/blogs/:blog', function(request, response) {
   setBasicHeader(response);
   response.send(post("blogs", request.params.blog, "index"));
});

nodePress.get('/posts/blogs/:blog/:post', function(request, response) {
   setBasicHeader(response);
   response.send(post("blogs", request.params.blog, request.params.post));
});

nodePress.get('/posts/news/:news', function(request, response) {
   setBasicHeader(response);
   response.send(post("news", request.params.news, "index"));
});

nodePress.get('/posts/news/:news/:post', function(request, response) {
   setBasicHeader(response);
   response.send(post("news", request.params.news, request.params.post));
});

nodePress.get('/:page', function(request, response) {
   setBasicHeader(response);
   response.send(page(request.params.page));
});

这部分代码定义了实现 Web 服务器所需的所有路由。所有路由都运行 setBasicHeader() 函数来设置正确的标头值。所有针对页面类型的请求都会调用 page() 函数,而所有针对 post 类型页面的请求都会调用 posts() 函数。

Content-Type 的默认值为 HTML。因此,对于 CSS、JavaScript 和图像,Content-Type 显式设置为其适当的值。

您还可以使用 putdeletepost REST 动词定义路由。这个简单的服务器仅使用 get 动词。

//
// Start the server.
//
var addressItems = parts['ServerAddress'].split(':');
var server = nodePress.listen(addressItems[2], function() {
   var host = server.address().address;
   var port = server.address().port;

   console.log('nodePress is listening at http://%s:%s', host, port);
});

在定义所使用的不同函数之前要做的最后一件事是启动服务器。 server.json 文件包含 DNS 名称(此处为 localhost)和服务器的端口。解析后,服务器的 listen() 函数使用端口号来启动服务器。服务器端口打开后,脚本会记录服务器的地址和端口。

//
// Function:     	setBasicHeader
//
// Description: 	This function will set the basic header information
// 					needed.
//
// Inputs:
//						response 		The response object
//
function setBasicHeader(response) {
   response.append("Cache-Control", "max-age=2592000, cache");
   response.append("Server", "nodePress - a CMS written in node from Custom Computer Tools: http://customct.com.");
}

定义的第一个函数是 setBasicHeader() 函数。该函数设置响应头,告诉浏览器将页面缓存一个月。它还告诉浏览器该服务器是nodePress服务器。如果您需要任何其他标准标头值,您可以使用 response.append() 函数在此处添加它们。

//
// Function:         page
//
// Description:      This function processes a page request
//
// Inputs:
//                  page 		The requested page
//
function page(page) {
   //
   // Process the given page using the standard layout.
   //
   return (processPage(parts["layout"], parts['Sitebase'] + "pages/" + page));
}

page() 函数将页面的布局模板以及页面在服务器上的位置发送到 processPage() 函数。

//
// Function:         post
//
// Description:      This function processes a post request
//
// Inputs:
//                  type 		The type of post.
//                  cat 		The category of the post.
//                  post 		The requested post
//
function post(type, cat, post) {
   //
   // Process the post given the type and the post name.
   //
   return (processPage(parts["layout"], parts['Sitebase'] + "posts/" + type + "/" + cat + "/" + post));
}

post() 函数就像 page() 函数,不同之处在于帖子有更多项目来定义每个帖子。在这个系列的服务器中,一个post包含一个type、category,以及实际的post。类型为 blogsnews。类别是 flatcms。由于这些代表目录名称,因此您可以将它们设为您想要的任何名称。只需将命名与文件系统中的名称相匹配即可。

//
// Function:         processPage
//
// Description:      This function processes a page for the CMS.
//
// Inputs:
//                  layout 		The layout to use for the page.
//                  page 			Path to the page to render.
//
function processPage(layout, page) {
   //
   // Get the pages contents and add to the layout.
   //
   var context = {};
   context = MergeRecursive(context, parts);
   context['content'] = figurePage(page);
   context['PageName'] = path.basename(page, path.extname(page));

   //
   // Load page data.
   //
   if(fileExists(page + ".json")) {
   	//
   	// Load the page's data file and add it to the data structure.
   	//
   	context = MergeRecursive(context, JSON.parse(fs.readFileSync(page + '.json', 'utf8')));
   }

   //
   // Process Handlebars codes.
   //
   var template = Handlebars.compile(layout);
   var html = template(context);

   //
   // Process all shortcodes.
   //
   html = processShortCodes(html);

   //
   // Run through Handlebars again.
   //
   template = Handlebars.compile(html);
   html = template(context);

   //
   // Return results.
   //
   return (html);
}

processPage() 函数获取要呈现的页面内容的布局和路径。该函数首先创建 parts 全局变量的本地副本,并添加“contents”主题标签以及调用 figurePage() 函数的结果。然后,它将 PageName 哈希值设置为页面名称。

然后,该函数使用 Handlebars 将页面内容编译到布局模板。之后, processShortCodes() 函数将展开页面上定义的所有短代码。然后,Handlebars 模板引擎再次检查代码。然后浏览器接收结果。

//
// Function:     	processShortCodes
//
// Description: 	This function takes a string and
// 					processes all of the shortcodes in 
// 					the string.
//
// Inputs:
// 					content 		String to process
//
function processShortCodes(content) {
   //
   // Create the results variable.
   //
   var results = "";

   //
   // Find the first match.
   //
   var scregFind = /\-\[([^\]]*)\]\-/i;
   var match = scregFind.exec(content);
   if (match != null) {
   	results += content.substr(0,match.index);
      var scregNameArg = /(\w+)(.*)*/i;
      var parts = scregNameArg.exec(match[1]);
      if (parts != null) {
         //
         // Find the closing tag.
         //
         var scregClose = new RegExp("\\-\\[\\/" + parts[1] + "\\]\\-");
         var left = content.substr(match.index + 4 + parts[1].length);
         var match2 = scregClose.exec(left);
         if (match2 != null) {
            //
            // Process the enclosed shortcode text.
            //
            var enclosed = processShortCodes(content.substr(match.index + 4 + parts[1].length, match2.index));

            //
            // Figure out if there were any arguments.
            //
            var args = "";
            if (parts.length == 2) {
               args = parts[2];
            }

            //
            // Execute the shortcode.
            //
            results += shortcodes[parts[1]](args, enclosed);

            //
            // Process the rest of the code for shortcodes.
            //
            results += processShortCodes(left.substr(match2.index + 5 + parts[1].length));
         } else {
            //
            // Invalid shortcode. Return full string.
            //
            results = content;
         }
      } else {
         //
         // Invalid shortcode. Return full string.
         //
         results = content;
      }
   } else {
      //
      // No shortcodes found. Return the string.
      //
      results = content;
   }
   return (results);
}

processShortCodes() 函数将网页内容作为字符串并搜索所有短代码。短代码是类似于 HTML 标签的代码块。一个例子是:

-[box]-
    <p>This is inside a box</p>
-[/box]-

此代码在 HTML 段落周围有一个 box 的简码。其中 HTML 使用 >>,短代码使用 -[ 和 >]-。在名称后面,可以包含或不可以包含包含短代码参数的字符串。

processShortCodes() 函数查找短代码,获取其名称和参数,找到末尾以获取内容,处理短代码的内容,使用参数和内容执行短代码,将结果添加到完成中页面,并在页面的其余部分搜索下一个短代码。循环是通过递归调用函数来执行的。

//
// Define the shortcodes function array.
//
var shortcodes = {
   'box': function(args, inside) {
      return ("<div class='box'>" + inside + "</div>");
   },
   'Column1': function(args, inside) {
      return ("<div class='col1'>" + inside + "</div>");
   },
   'Column2': function(args, inside) {
      return ("<div class='col2'>" + inside + "</div>");
   },
   'Column1of3': function(args, inside) {
      return ("<div class='col1of3'>" + inside + "</div>");
   },
   'Column2of3': function(args, inside) {
      return ("<div class='col2of3'>" + inside + "</div>");
   },
   'Column3of3': function(args, inside) {
      return ("<div class='col3of3'>" + inside + "</div>");
   },
   'php': function(args, inside) {
      return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: php'>" + inside + "
"); }, 'js': function(args, inside) { return ("
" + inside + "
"); }, 'html': function(args, inside) { return ("
" + inside + "
"); }, 'css': function(args, inside) { return ("
" + inside + "
"); } };

下一节定义 shortcodes json 结构,该结构定义与其函数关联的短代码的名称。所有短代码函数都接受两个参数:argsinsideargs 是名称和空格之后、标签结束之前的所有内容。 inside 是开始和结束短代码标记包含的所有内容。这些功能是基本功能,但您可以创建一个短代码来执行您能在 JavaScript 中想到的任何功能。

//
// Function:        figurePage
//
// Description:     This function figures the page type
//                  and loads the contents appropriately
//                  returning the HTML contents for the page.
//
// Inputs:
//                  page 			The page to load contents.
//
function figurePage(page) {
   var result = "";

   if (fileExists(page + ".html")) {
      //
      // It's an HTML file. Read it in and send it on.
      //
      result = fs.readFileSync(page + ".html");
   } else if (fileExists(page + ".amber")) {
      //
      // It's a jade file. Convert to HTML and send it on. I
      // am still using the amber extension for compatibility
      // to goPress.
      //
      var jadeFun = jade.compileFile(page + ".amber", {});

      // Render the function
      var result = jadeFun({});
   } else if (fileExists(page + ".md")) {
      //
      // It's a markdown file. Convert to HTML and send
      // it on.
      //
      result = marked(fs.readFileSync(page + ".md").toString());

      //
      // This undo marked's URI encoding of quote marks.
      //
      result = result.replace(/\&quot\;/g,"\"");
   }

   return (result);
}

figurePage() 函数接收服务器上页面的完整路径。然后,此函数根据扩展名测试它是否为 HTML、Markdown 或 Jade 页面。我仍然在 Jade 中使用 .amber,因为那是我在 goPress 服务器上使用的库。所有 Markdown 和 Jade 内容都会先转换为 HTML,然后再传递给调用例程。由于 Markdown 处理器将所有引号翻译为 ",因此我在传回之前将它们翻译回来。

//
// Function:     	fileExists
//
// Description: 	This function returns a boolean true if 
// 					the file exists. Otherwise, false.
//
// Inputs:
// 					filePath 	Path to a file in a string.
//
function fileExists(filePath) {
   try {
      return fs.statSync(filePath).isFile();
   } catch (err) {
      return false;
   }
}

fileExists() 函数是 fs.exists() 函数的替代品,该函数曾经是 Node.js 的 fs 库的一部分。它使用 fs.statSync() 函数来尝试获取文件的状态。如果发生错误,则会返回 false。否则,返回 true

//
//  Function:        MergeRecursive
//
//  Description:     Recursively merge properties of two objects
//
//  Inputs:
//                   obj1    The first object to merge
//                   obj2    The second object to merge
//
function MergeRecursive(obj1, obj2) {

   for (var p in obj2) {
      try {
         // Property in destination object set; update its value.
         if (obj2[p].constructor == Object) {
            obj1[p] = MergeRecursive(obj1[p], obj2[p]);

         } else {
            obj1[p] = obj2[p];

         }

      } catch (e) {
         // Property in destination object not set; create it and set its value.
         obj1[p] = obj2[p];

      }
   }

   return obj1;
}

最后一个函数是 MergeRecursive() 函数。它将第二个传递对象复制到第一个传递对象中。在添加特定于页面的部分之前,我利用它将主 parts 全局变量复制到本地副本中。

本地运行

保存文件后,您可以使用以下命令运行服务器:

node nodePress.js

或者,您可以使用 package.json 文件中的 npm 脚本。您可以像这样运行 npm 脚本:

npm start

这将运行 package.json 文件内的 start 脚本。

"建立內容管理系統:nodePress"

将您的网络浏览器指向 http://localhost:8080,您将看到上面的页面。您可能已经注意到我在主页上添加了更多测试代码。对页面的所有更改都包含在本教程的下载中。它们大多只是一些小的调整,以更全面地测试功能并适应使用不同库的任何差异。最显着的区别是 Jade 库不使用 $ 来命名变量,而 Amber 则使用。

结论

现在,您在 Go 和 Node.js 中拥有完全相同的平面文件系统 CMS。这只是您可以使用此平台构建的内容的表面。尝试并尝试新事物。这是创建您自己的网络服务器的最佳部分。

以上是建立內容管理系統:nodePress的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具