🔍 搜尋結果:javasc

🔍 搜尋結果:javasc

設計模式 #4 - 發布者/訂閱者模式

在本系列的前一篇文章中,我介紹了[觀察者模式](https://dev.to/superviz/design-pattern-3-observer-pattern-36eo)。今天,我想與大家分享發布者和訂閱者模式,或是最親密的朋友的 PubSub 模式。我強烈建議您在繼續此任務之前閱讀並理解觀察者模式。 酒吧子圖案設計 ------- PubSub 模式是一種促進鬆散耦合和可擴展性的訊息傳遞模式。此模式圍繞著將訊息從發布者分派到未指定數量的訂閱者或偵聽器,從而促進物件之間的多對多依賴關係。 ### 真實案例場景 讓我們考慮一個聊天群組應用程式。 Pub/Sub系統可以有效率地處理訊息的發送和接收: #### 訂閱活動 當聊天視窗開啟時,它會訂閱一個事件,例如`newMessage` 。 這是使用`pubsub.subscribe("newMessage", callback)`完成的。回呼函數是當新訊息發佈到`newMessage`事件時將執行的函數。在這種情況下,回呼會記錄新訊息並更新聊天 UI。 ``` pubsub.subscribe("newMessage", function(data) { console.log("New message received:", data); // Here you would update the chat UI with the new message }); ``` #### 發佈到活動 當使用者傳送訊息時,會使用 pubsub.publish("newMessage", messageData) 發佈至 newMessage 事件。所有訂閱 newMessage 主題的聊天視窗都將使用新訊息作為參數來執行其回呼函數。 當使用者傳送訊息時,它會使用`pubsub.publish("newMessage", messageData)`發佈到`newMessage`事件。所有訂閱`newMessage`主題的聊天視窗都將使用新訊息作為參數來執行其回呼函數。 ``` const messageData = { user: "User A", text: "This is what the user had typed" }; pubsub.publish("newMessage", messageData); ``` 這樣,Pub/Sub 系統就實作了聊天視窗(訂閱者)和訊息發送者(發布者)的解耦。聊天視窗不需要知道誰發送了訊息(就像我們在之前關於觀察者模式的貼文中看到的那樣),它們只需要知道收到訊息後要做什麼。 同樣,訊息發送者不需要知道誰將收到訊息;只需知道訊息發送者將收到訊息即可。他們只需要將訊息發送到正確的主題。 ### 如何建立一個酒吧訂閱伺服器 為了建立 PubSub 系統,我們需要維護事件或「主題」及其各自訂閱者的記錄。這可以透過一個簡單的 JavaScript 物件來完成。當發布新訊息時,我們會尋找關聯的訂閱者並執行他們的回呼函數。這允許動態且靈活的系統,可以在執行時新增或刪除發布者和訂閱者。 ``` class PubSub { static events = {}; // It has the an empty list of events // The subscribe method takes an event name and a callback function subscribe(eventName, callback) { if (!this.events[eventName]) { // If the event doesn't exist yet, initialize it as an empty array this.events[eventName] = []; } // Push the callback function into the array of callbacks for the given event this.events[eventName].push(callback); } // The publish method takes an event name and data publish(event, data) { // If the event doesn't exist, or there's no subscribers for this event, return if (!this.events[event]) { return; } // For each subscriber of this event, call the callback function with the provided data this.events[event].forEach((callback) => { callback(data); }); } } ``` 讓我稍微分解一下這段程式碼: `PubSub`類別有一個靜態`events`屬性,它是一個儲存所有事件(或主題)及其對應訂閱者(回呼函數)的物件。 `subscribe`方法用於為給定事件註冊新訂閱者。它採用事件名稱和回呼函數作為參數。如果事件尚不存在,它將在`events`物件中將其初始化為空陣列。然後,它將回調函數加入到給定事件的回調陣列中。 `publish`方法用於將新資料發佈到事件。它採用事件名稱和要發布的資料作為參數。如果該事件不存在或沒有該事件的訂閱者,則它只是返回並且不執行任何操作。如果有訂閱者,它會呼叫每個訂閱者的回呼函數,並將發布的資料作為參數傳遞。 在聊天應用程式的上下文中, `subscribe`方法將用於註冊應接收新訊息的新聊天窗口,而`publish`方法將用於將新訊息發送到已訂閱接收新訊息的所有聊天窗口。 您可以透過以下文章詳細了解如何跨裝置使用發布和訂閱方法: [**了解並實現前端開發中的事件驅動通訊**](https://dev.to/superviz/understanding-and-implementing-event-driven-communication-in-front-end-development-e75)。 即時資料引擎 ------ 這是軟體開發架構的重要組成部分,但在大多數情況下,這並不是您正在建立的業務核心。建立一個可靠且可擴展的 PubSub 系統來在應用程式的不同實例之間同步資料可能具有挑戰性。 我們已經到了 2024 年,這意味著已經有了解決方案:[即時資料引擎](https://docs.superviz.com/react-sdk/presence/real-time-data-engine)工具,特別是[SuperViz SDK](http://superviz.com/) 。它提供即時協作和通訊 SDK 和 API,專為建立即時 Web 應用程式的開發人員而設計。 使用 SuperViz,您可以建立一個包含多個參與者的房間,當發布事件時,該事件會將廣播給房間中透過不同裝置和網路存取該事件的所有參與者。這意味著一個參與者所做的任何更新都將即時反映在所有裝置上,從而提供無縫的協作體驗。 [SuperViz](http://superviz.com/)提供建立即時協作應用程式所需的基礎架構。這包括使用 Webhooks 在後端捕獲此事件的能力,以及使用簡單 HTTP 請求發布事件的能力,僅舉幾個功能。 請在評論中告訴我您還想了解哪些其他設計模式,並且不要忘記分享您的知識! --- 原文出處:https://dev.to/superviz/design-pattern-4-publishersubscriber-pattern-4jg9

開發人員的綜合 React.js 備忘單

React.js 已成為現代 Web 開發的基石,用於建立動態和高效能 Web 應用程式。這份全面的備忘單將涵蓋您掌握 React.js 所需了解的所有內容,包括實際範例、程式碼片段以及所有功能的詳細說明。目標是提供可供您隨時參考的深入指南。 ### 目錄 1. 反應簡介 2. 開始使用 React - 設定環境 - 建立一個新的 React 應用程式 3. 反應元件 - 功能元件 - 類別元件 - 功能元件和類別元件之間的差異 4. JSX - JSX 語法 - 嵌入表達式 - JSX 屬性 5. 狀態和道具 - 了解狀態 - 使用 useState Hook 管理狀態 - 了解道具 - 傳遞道具 - 道具類型和預設道具 6. 元件生命週期 - 類別元件中的生命週期方法 - 使用 useEffect 鉤子 - 使用 useEffect 進行清理 7. 處理事件 - React 中的事件處理 - 綜合事件 - 處理表格 - 事件處理程序最佳實踐 8. 條件渲染 - if-else 語句 - 三元運算符 - 邏輯 &amp;&amp; 運算符 - 內嵌 If 與邏輯 &amp;&amp; 運算符 9. 列表和鍵 - 渲染列表 - 使用按鍵 - 鍵只能在兄弟姊妹中是唯一的 10. 表單和受控元件 ``` - Handling Form Data ``` ``` - Controlled vs Uncontrolled Components ``` ``` - Using Refs for Uncontrolled Components ``` ``` - Form Validation ``` 11. 反應路由器 ``` - Setting Up React Router ``` ``` - Route Parameters ``` ``` - Nested Routes ``` ``` - Redirects and Navigation ``` 12. 上下文API ``` - Creating Context ``` ``` - Consuming Context ``` ``` - Context with Functional Components ``` ``` - Updating Context ``` ``` - Context Best Practices ``` 13. 掛鉤 ``` - Basic Hooks (useState, useEffect) ``` ``` - Additional Hooks (useContext, useReducer) ``` ``` - Custom Hooks ``` ``` - Rules of Hooks ``` 14. 高階元件 (HOC) ``` - Understanding HOCs ``` ``` - Creating HOCs ``` ``` - Using HOCs ``` ``` - HOC Best Practices ``` 15. 誤差邊界 ``` - Implementing Error Boundaries ``` ``` - Catching Errors ``` ``` - Error Boundaries Best Practices ``` 16. 反應性能優化 ``` - Memoization ``` ``` - Code Splitting ``` ``` - Lazy Loading ``` ``` - React Profiler ``` 17. 在 React 中測試 ``` - Unit Testing with Jest ``` ``` - Component Testing with React Testing Library ``` ``` - End-to-End Testing with Cypress ``` ``` - Testing Best Practices ``` --- ### 1.React簡介 React.js 通常簡稱為 React,是一個開源 JavaScript 函式庫,用於建立使用者介面,特別是對於需要快速互動式使用者體驗的單頁應用程式。 React 由 Facebook 開發,允許開發人員建立大型 Web 應用程式,這些應用程式可以有效地更新和渲染以回應資料變更。 React 的核心概念是元件,它是一個獨立的模組,可以呈現一些輸出。元件可以獨立嵌套、管理和處理,使開發過程高效且可維護。 ### 2. React 入門 #### 設定環境 在開始使用React之前,您需要設定開發環境。就是這樣: 1. **安裝 Node.js 和 npm** :React 依賴 Node.js 和 npm(節點套件管理器)來管理相依性。 - 從[官方網站](https://nodejs.org/)下載並安裝 Node.js。 - 透過執行以下命令驗證安裝: ``` node -v npm -v ``` 2. **安裝 Create React App** :Create React App 是學習 React 的舒適環境,也是在 React 中啟動新的單頁應用程式的好方法。 ``` npm install -g create-react-app ``` #### 建立一個新的 React 應用程式 一旦環境設定完畢,您就可以建立一個新的 React 應用程式。 1. **建立一個新專案**: ``` npx create-react-app my-app cd my-app npm start ``` 此命令建立一個具有指定名稱( `my-app` )的新目錄,設定一個新的 React 專案,並啟動開發伺服器。您可以開啟瀏覽器並造訪`http://localhost:3000`來查看新的 React 應用程式。 ### 3. 反應元件 元件是任何 React 應用程式的建置塊。它們讓您可以將 UI 分成獨立的、可重複使用的部分。 #### 功能元件 函數式元件是接受 props 作為參數並傳回 React 元素的 JavaScript 函數。它們比類別元件更簡單、更容易編寫。 ``` import React from 'react'; const Welcome = ({ name }) => { return <h1>Welcome, {name}!</h1>; }; export default Welcome; ``` #### 類別元件 類別元件是擴展`React.Component`的 ES6 類,並具有傳回 React 元素的 render 方法。 ``` import React, { Component } from 'react'; class Welcome extends Component { render() { return <h1>Welcome, {this.props.name}!</h1>; } } export default Welcome; ``` #### 功能元件和類別元件之間的差異 - **狀態管理**:功能元件使用鉤子( `useState` 、 `useEffect`等)進行狀態管理,而類別元件則使用`this.state`和生命週期方法。 - **生命週期方法**:類別元件具有生命週期方法,例如`componentDidMount` 、 `componentDidUpdate`和`componentWillUnmount` 。功能元件使用`useEffect`鉤子來處理副作用。 - **簡單性**:函數式元件更簡單、更簡潔,使它們更易於閱讀和維護。 ### 4.JSX JSX 是一種語法擴展,可讓您直接在 JavaScript 中編寫 HTML。它產生 React“元素”。 #### JSX 語法 JSX 看起來像 HTML,但被轉換為 JavaScript。 ``` const element = <h1>Hello, world!</h1>; ``` #### 嵌入表達式 您可以透過將任何 JavaScript 表達式括在大括號中來將其嵌入到 JSX 中。 ``` const name = 'John'; const element = <h1>Hello, {name}!</h1>; ``` #### JSX 屬性 JSX 允許您使用類似 HTML 的語法的屬性。 ``` const element = <img src={user.avatarUrl} alt={user.name} />; ``` ### 5. 狀態和道具 #### 了解狀態 State 是一個內建物件,用來儲存屬於元件的屬性值。當狀態物件發生變化時,元件會重新渲染。 #### 使用 useState Hook 管理狀態 `useState`鉤子用於向功能元件加入狀態。 ``` import React, { useState } from 'react'; const Counter = () => { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }; export default Counter; ``` #### 了解道具 Props 是傳遞給 React 元件的參數。 Props 透過 HTML 屬性傳遞給元件。 #### 傳遞道具 道具是唯讀且不可變的。 ``` const Greeting = (props) => { return <h1>Hello, {props.name}!</h1>; }; const App = () => { return <Greeting name="Alice" />; }; ``` #### 道具類型和預設道具 PropTypes 可讓您定義元件應接收的 props 類型。可以定義預設 props 以確保 prop 在未指定的情況下具有值。 ``` import React from 'react'; import PropTypes from 'prop-types'; const Greeting = ({ name }) => { return <h1>Hello, {name}!</h1>; }; Greeting.propTypes = { name: PropTypes.string.isRequired, }; Greeting.defaultProps = { name: 'Guest', }; export default Greeting; ``` ### 6. 元件生命週期 #### 類別元件中的生命週期方法 生命週期方法是類別元件中的特殊方法,它們在元件生命週期的特定點執行。 - **componentDidMount** :在元件渲染後執行。 - **componentDidUpdate** :在元件的更新刷新到 DOM 後執行。 - **componentWillUnmount** :在元件從 DOM 中刪除之前執行。 ``` class MyComponent extends React.Component { componentDidMount() { // Runs after component is mounted } componentDidUpdate(prevProps, prevState) { // Runs after component updates } componentWillUnmount() { // Runs before component is unmounted } render() { return <div>My Component</div>; } } ``` #### 使用 useEffect 鉤子 `useEffect`掛鉤結合了`componentDidMount` 、 `componentDidUpdate`和`componentWillUnmount`的功能。 ``` import React, { useState, useEffect } from 'react'; const MyComponent = () => { const [count, setCount] = useState(0); useEffect(() => { // Runs on mount and update document.title = `You clicked ${count} times`; // Cleanup function (runs on unmount) return () => { console.log('Cleanup'); }; }, [count]); // Dependency array return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }; export default MyComponent; ``` ### 7. 處理事件 #### React 中的事件處理 React 事件使用駝峰式命名,而不是小寫。使用 JSX,您可以傳遞一個函數作為事件處理程序,而不是一個字串。 ``` const handleClick = () => { console.log('Button clicked'); }; const MyComponent = () => { return <button onClick={handleClick}>Click me</button>; }; ``` #### 綜合事件 React 的事件系統稱為綜合事件。它是瀏覽器本機事件系統的跨瀏覽器包裝器。 #### 處理表格 在 React 中處理表單涉及控制輸入元素和管理狀態。 ``` import React, { useState } from 'react'; const MyForm = () => { const [value, setValue] = useState(''); const handleChange = (event) => { setValue(event.target.value); }; const handleSubmit = (event) => { event.preventDefault(); alert('A name was submitted: ' + value); }; return ( <form onSubmit={handleSubmit}> <label> Name: <input type="text" value={value} onChange={handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); }; export default MyForm; ``` #### 事件處理程序最佳實踐 - **避免內聯事件處理程序**:在 JSX 外部定義事件處理程序,以獲得更好的可讀性和效能。 - **使用箭頭函數**:使用箭頭函數可以避免`this`綁定出現問題。 - **去抖昂貴的操作**:去抖昂貴的操作(如 API 呼叫)以避免效能問題。 ### 8. 條件渲染 #### if-else 語句 您可以在`render`方法中使用 JavaScript if-else 語句。 ``` const MyComponent = ({ isLoggedIn }) => { if (isLoggedIn) { return <h1>Welcome back!</h1>; } else { return <h1>Please sign in.</h1>; } }; ``` #### 三元運算符 三元運算子是執行條件渲染的簡潔方法。 ``` const MyComponent = ({ isLoggedIn }) => { return ( <div> {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>} </div> ); }; ``` #### 邏輯 &amp;&amp; 運算符 您可以使用邏輯 &amp;&amp; 運算子有條件地包含元素。 ``` const MyComponent = ({ isLoggedIn }) => { return ( <div> {isLoggedIn && <h1>Welcome back!</h1>} </div> ); }; ``` #### 內嵌 If 與邏輯 &amp;&amp; 運算符 帶有邏輯 &amp;&amp; 運算子的內聯 if 允許您有條件地在輸出中包含元素。 ``` const Mailbox = ({ unreadMessages }) => { return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); }; ``` ### 9. 列表和鍵 #### 渲染列表 您可以建立元素集合並使用大括號`{}`將它們包含在 JSX 中。 ``` const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); const NumberList = () => { return ( <ul>{listItems}</ul> ); }; ``` #### 使用按鍵 鍵可協助 React 辨識哪些專案已變更、新增或刪除。應為陣列內的元素提供鍵,以便為元素提供穩定的標識。 ``` const NumberList = (props) => { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); }; ``` #### 鍵只能在兄弟姊妹中是唯一的 陣列中使用的鍵在其兄弟陣列中應該是唯一的。 ``` function Blog(props) { const sidebar = ( <ul> {props.posts.map((post) => <li key={post.id}> {post.title} </li> )} </ul> ); const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3> <p>{post.content}</p> </div> ); return ( <div> {sidebar} <hr /> {content} </div> ); } ``` ### 10. 表格和受控元件 #### 處理表單資料 在 React 中處理表單資料涉及管理表單欄位的狀態。 ``` import React, { useState } from 'react'; const MyForm = () => { const [value, setValue] = useState(''); const handleChange = (event) => { setValue(event.target.value); }; const handleSubmit = (event) => { event.preventDefault(); alert('A name was submitted: ' + value); }; return ( <form onSubmit={handleSubmit}> <label> Name: <input type="text" value={value} onChange={handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); }; export default MyForm; ``` #### 受控元件與非受控元件 受控元件是由 React 狀態控制的元件。不受控制的元件是那些維持其自身內部狀態的元件。 ``` class NameForm extends React.Component { constructor(props) { super(props); this.state = { value: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({ value: event.target.value }); } handleSubmit(event) { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); } } ``` #### 對不受控制的元件使用引用 Refs 提供了一種存取 DOM 節點或在 render 方法中建立的 React 元素的方法。 ``` class NameForm extends React.Component { constructor(props) { super(props); this.input = React.createRef(); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { alert('A name was submitted: ' + this.input.current.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={this.input} /> </label> <input type="submit" value="Submit" /> </form> ); } } ``` #### 表單驗證 表單驗證可確保使用者輸入有效。 ``` const MyForm = () => { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [error, setError] = useState(''); const handleSubmit = (event) => { event.preventDefault(); if (!name || !email) { setError('Name and Email are required'); } else { setError(''); // Submit form } }; return ( <form onSubmit={handleSubmit}> {error && <p>{error}</p>} <label> Name: <input type="text" value={name} onChange={(e) => setName(e.target.value)} /> </label> <label> Email: <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} /> </label> <input type="submit" value="Submit" /> </form> ); }; export default MyForm; ``` ### 11.反應路由器 React Router 是一個用於在 React 應用程式中進行路由的函式庫。它允許您根據 URL 處理不同元件的導航和渲染。 #### 設定 React 路由器 1. **安裝反應路由器**: ``` npm install react-router-dom ``` 2. **設定路線**: ``` import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; const Home = () => <h2>Home</h2>; const About = () => <h2>About</h2>; const App = () => { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Switch> </Router> ); }; export default App; ``` #### 路由參數 您可以使用路由參數從 URL 擷取值。 ``` import React from 'react'; import { BrowserRouter as Router, Route, Switch, useParams } from 'react-router-dom'; const User = () => { const { id } = useParams(); return <h2>User ID: {id}</h2>; }; const App = () => { return ( <Router> <Switch> <Route path="/user/:id" component={User} /> </Switch> </Router> ); }; export default App; ``` #### 嵌套路由 嵌套路由可讓您在父元件內渲染子元件。 ``` import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link, useRouteMatch } from 'react-router-dom'; const Topic = ({ match }) => <h3>Requested Topic ID: {match.params.topicId}</h3>; const Topics = ({ match }) => { let { path, url } = useRouteMatch(); return ( <div> <h2>Topics</h2> <ul> <li> <Link to={`${url}/components`}>Components</Link> </li> <li> <Link to={`${url}/props-v-state`}>Props v. State</Link> </li> </ul> <Switch> <Route exact path={path}> <h3>Please select a topic.</h3> </Route> <Route path={`${path}/:topicId`} component={Topic} /> </Switch> </div> ); }; const App = () => { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/topics">Topics</Link> </li> </ul> <hr /> <Switch> <Route exact path="/" component={Home} /> <Route path="/topics" component={Topics} /> </Switch> </div> </Router> ); }; export default App; ``` #### 重定向和導航 您可以使用`Redirect`元件以程式設計方式重定向到不同的路由。 ``` import React from 'react'; import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; const Home = () => <h2>Home</h2>; const About = () => <h2>About</h2>; const App = () => { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Redirect from="/old-path" to="/new-path" /> </Switch> </Router> ); }; export default App; ``` ### 12. 上下文API Context API 提供了一種透過元件樹傳遞資料的方法,而無需在每個層級手動向下傳遞 props。 #### 建立上下文 若要建立上下文,請使用`React.createContext` 。 ``` const MyContext = React.createContext(); ``` #### 消費環境 若要使用上下文值,請在功能元件中使用`useContext`掛鉤,或在類別元件中使用`Context.Consumer` 。 ``` const MyComponent = () => { const value = useContext(MyContext); return <div>{value}</div>; }; ``` #### 功能元件的上下文 ``` const MyComponent = () => { return ( <MyContext.Provider value="Hello"> <AnotherComponent /> </MyContext.Provider> ); }; const AnotherComponent = () => { const value = useContext(MyContext); return <div>{value}</div>; }; ``` #### 更新情境 若要更新上下文,請建立一個具有狀態的提供者元件。 ``` const MyProvider = ({ children }) => { const [value, setValue] = useState('Hello'); return ( <MyContext.Provider value={{ value, setValue }}> {children} </MyContext.Provider> ); }; const MyComponent = () => { const { value, setValue } = useContext(MyContext); return ( <div> {value} <button onClick={() => setValue('Updated Value')}>Update</button> </div> ); }; ``` #### 情境最佳實踐 - **避免過度使用上下文**:謹慎使用上下文,並且僅針對全域資料。 - **使用多個上下文**:透過使用多個上下文來分離關注點。 - **記憶上下文值**:使用`useMemo`來避免不必要的重新渲染。 ### 13. 掛鉤 Hooks 是允許您在功能元件中使用狀態和其他 React 功能的函數。 #### 基本 Hooks(useState、useEffect) - **useState** :向功能元件新增狀態。 - **useEffect** :在功能元件中執行副作用。 #### 附加掛鉤(useContext、useReducer) - **useContext** :存取上下文值。 - **useReducer** :管理複雜的狀態邏輯。 ``` const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> Count: {state.count} <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </div> ); } ``` #### 定制掛鉤 自訂鉤子是封裝邏輯的函數,可以跨元件重複使用。 ``` const useFetch = (url) => { const [data, setData] = useState(null); useEffect(() => { fetch(url) .then((response) => response.json()) .then((data) => setData(data)); }, [url]); return data; }; const MyComponent = () => { const data = useFetch('https://api.example.com/data'); return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>; }; ``` #### 鉤子規則 - **在頂層呼叫鉤子**:不要在循環、條件或巢狀函數內呼叫鉤子。 - **僅從 React 函數呼叫鉤子**:從功能元件或自訂鉤子呼叫鉤子。 ### 14. 高階元件(HOC) 高階元件 (HOC) 是獲取元件並傳回新元件的函數。 #### 了解 HOC HOC 用於為元件新增附加功能。 ``` const withLogging = (WrappedComponent) => { return (props) => { console.log('Rendering', WrappedComponent.name); return <WrappedComponent {...props} />; }; }; ``` #### 建立 HOC ``` const EnhancedComponent = withLogging(MyComponent); ``` #### 使用 HOC ``` const MyComponent = (props) => { return <div>My Component</div>; }; const EnhancedComponent = withLogging(MyComponent); ``` #### HOC 最佳實踐 - **不要改變原始元件**:傳回一個新元件。 - **使用顯示名稱進行偵錯**:在 HOC 上設定`displayName`以便更好地進行偵錯。 ### 15. 誤差邊界 錯誤邊界是 React 元件,它可以在其子元件樹中的任何位置捕獲 JavaScript 錯誤、記錄這些錯誤並顯示後備 UI。 #### 實施誤差邊界 錯誤邊界會在渲染期間、生命週期方法以及其下方的整個樹的構造函數中捕獲錯誤。 ``` class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { // You can also log the error to an error reporting service console.log(error, errorInfo); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } ``` #### 捕獲錯誤 錯誤邊界捕捉渲染方法和生命週期方法中的錯誤。 ``` const MyComponent = () => { throw new Error('An error occurred'); return <div>My Component</div>; }; const App = () => { return ( <ErrorBoundary> <MyComponent /> </ErrorBoundary> ); }; ``` #### 錯誤邊界最佳實踐 - **使用錯誤邊界捕獲元件中的錯誤**:使用錯誤邊界捕獲並顯示 UI 元件中的錯誤。 - **記錄錯誤以進行偵錯**:將錯誤記錄到外部服務以進行偵錯。 ### 16.React效能優化 #### 記憶化 記憶化有助於避免不必要的重新渲染元件。 ``` import React, { memo } from 'react'; const MyComponent = memo(({ value }) => { return <div>{value}</div>; }); ``` #### 程式碼分割 程式碼分割有助於僅載入必要的程式碼並提高效能。 ``` import React, { Suspense, lazy } from 'react'; const OtherComponent = lazy(() => import('./OtherComponent')); const MyComponent = () => { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); }; ``` #### 延遲載入 延遲載入有助於僅在需要時載入元件。 ``` import React, { Suspense, lazy } from 'react'; const Other Component = lazy(() => import('./OtherComponent')); const MyComponent = () => { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); }; ``` #### useMemo 和 useCallback - **useMemo** :記住昂貴的計算。 - **useCallback** :記憶函數。 ``` const MyComponent = ({ value }) => { const memoizedValue = useMemo(() => { return computeExpensiveValue(value); }, [value]); const memoizedCallback = useCallback(() => { doSomething(value); }, [value]); return ( <div> {memoizedValue} <button onClick={memoizedCallback}>Click me</button> </div> ); }; ``` #### 反應開發者工具 使用 React Developer Tools 來辨識效能瓶頸。 ### 17. 在 React 中測試 #### Jest 和 React 測試函式庫 Jest 和 React 測試庫是測試 React 元件的熱門工具。 #### 編寫測試 - **快照測試**:捕獲渲染的元件並將其與已儲存的快照進行比較。 - **單元測試**:測試各個元件和功能。 - **整合測試**:測試元件和服務之間的整合。 ``` import { render, screen } from '@testing-library/react'; import MyComponent from './MyComponent'; test('renders MyComponent', () => { render(<MyComponent />); const element = screen.getByText(/My Component/i); expect(element).toBeInTheDocument(); }); ``` ### 18.React 最佳實踐 #### 元件結構 - **依功能組織元件**:將相關元件分組在一起。 - **使用描述性名稱**:為元件和道具使用清晰且描述性的名稱。 - **保持元件較小**:將大型元件分解為較小的、可重複使用的元件。 #### 狀態管理 - **Lift state up** :將狀態提升到最近的共同祖先。 - **使用 Context 進行全域狀態**:使用 Context API 進行全域狀態管理。 #### 造型 - **使用 CSS 模組**:將 CSS 模組用於範圍化和模組化樣式。 - **使用樣式元件**:使用樣式元件進行動態樣式設定。 #### 表現 - **避免不必要的重新渲染**:使用記憶和 React 的內建效能最佳化工具。 - **使用程式碼拆分**:拆分程式碼以僅加載必要的元件。 #### 測試 - **編寫全面的測試**:為應用程式的所有關鍵部分編寫測試。 - **使用快照測試**:使用快照測試來擷取意外的變更。 ### 結論 React.js 是一個用於建立現代 Web 應用程式的強大函式庫。透過理解和利用其核心概念,您可以建立高效、可維護和可擴展的應用程式。這份備忘錄是幫助您掌握 React.js 的綜合指南,涵蓋從基本概念到高階主題的所有內容。 --- 原文出處:https://dev.to/raajaryan/comprehensive-reactjs-cheatsheet-for-developers-17e4

Polyfill 供應鏈攻擊將惡意軟體嵌入 JavaScript CDN 資產

2024 年 6 月 25 日,Sansec 安全研究和惡意軟體團隊[宣布](https://sansec.io/research/polyfill-supply-chain-attack),一個流行的JavaScript polyfill 專案已被一家被認定為中國公司的外國參與者接管,該專案將惡意程式碼嵌入從其CDN 來源取得的JavaScript 資產中: `cdn.polyfill.io` 。 Sansec 聲稱超過 100,000 個網站因這次 Polyfill 攻擊而受到影響,其中包括 Intuit 等上市公司。 惡意 Polyfill 函式庫發生了什麼事? --- Andrew Betts 是[polyfill Web 服務](https://github.com/polyfillpolyfill/polyfill-service)的原始作者。該專案允許根據使用者代理或其他屬性將 JavaScript 填充庫自動注入到網站中。 [Andrews 的聲明](https://x.com/triblondon/status/1761852117579427975)可以追溯到 2 月份,當時他們警告不要參與`cdn.polyfill.io`官方網站。 據我們所知,npm 上沒有特定的 polyfill 函式庫是該特定惡意行為者註入惡意程式碼活動的一部分。也就是說,跨不同軟體生態系統的函式庫(例如 Magento 專案等內容管理系統)可能包含引入來自`cdn.polyfill.io`的 JavaScript 程式碼的靜態腳本導入的程式碼。特別是,我們檢測到了 CVE-2024-38526,這是 PyPI 註冊表上`pdoc`庫的安全性報告,該註冊表為 Python 專案提供 API 文件。如果使用指令`pdoc --math`產生文件,則將包含來自`polyfill.io` JavaScript 文件的連結。 `pdoc`庫的這項行為已在pdoc版本14.5.1中修復,我們敦促用戶盡快升級。 什麼是 JavaScript 填色? --- JavaScript Polyfill 通常是專門建置的一段程式碼,可在本機不支援它的舊瀏覽器上提供現代功能。從歷史上看,polyfill 對於旨在建立跨不同瀏覽器版本無縫執行的應用程式的 Web 開發人員至關重要。它們充當橋樑,使較舊的瀏覽器能夠執行較新的 JavaScript 功能,從而確保無論瀏覽器的年齡或功能如何,都能提供一致的使用者體驗。 在 Web 開發的早期,瀏覽器以不同的速度發展,導致環境分散,相同的程式碼可能無法在所有平台上統一運作。一般來說,對瀏覽器 API 的支援不會得到同等支援。由於無法控制最終使用者可用的瀏覽器版本,開發人員無法保證在瀏覽器中執行 JavaScript 程式碼時可用的 API 相同。因此,polyfills 透過引入 polyfill 程式庫來解決這個問題,讓開發人員編寫現代 JavaScript 程式碼,而不必擔心相容性問題。例如,像`Array.prototype.includes`和`Promise`這樣的方法在 Internet Explorer 等舊版瀏覽器中不受支援。不過,開發人員可以透過瀏覽器中載入的 polyfill 程式庫來提供這些功能。 JavaScript CDN 在 polyfill 函式庫中的作用 --- 內容交付網路 (CDN) 是一個由全球部署的分散式伺服器組成的系統,可根據使用者的地理位置向使用者交付 Web 內容。在 JavaScript 填充庫的背景下,CDN 透過在全球範圍內有效地託管和服務這些庫而發揮著至關重要的作用。透過利用 CDN,開發人員可以確保將其 Polyfill 快速可靠地交付給用戶,從而最大限度地減少延遲並縮短載入時間。使用 CDN 也有助於開發人員避免捆綁 JavaScript 程式庫。 您可能遇到的 CDN 的一般用例是使用基於雲端的指標和應用程式效能,例如 Google Analytics,它正式建議您將以下程式碼新增至您的網站: ``` { "vars" : { "gtag\_id": "<GA\_MEASUREMENT\_ID>", "config" : { "<GA\_MEASUREMENT\_ID>": { "groups": "default" } } } } ``` 在惡意 Polyfill 接手的情況下, `cdn.polyfill.io`是一個廣泛使用的 CDN,它會根據傳入請求的 HTTP 標頭動態提供 Polyfill。這意味著根據使用者的瀏覽器和版本提供適當的polyfill,確保最佳相容性。 CDN 上託管的 Polyfill 的安全風險 --- 使用 CDN 上託管的 Polyfill 會帶來重大的安全風險,主要是因為在應用程式上下文中可能存在任意 JavaScript 程式碼執行的可能性。此風險通常被報告為給定 Web 應用程式的跨站點腳本 (XSS) 漏洞。 當從 CDN 取得 Polyfill 庫時,應用程式會依賴外部伺服器的完整性和安全性。正如 CDN 來源本身一樣。如果 CDN 或託管庫受到損害,如最近對`cdn.polyfill.io`的攻擊所示,新受到損害的程式碼可以在使用者的瀏覽器中註入並執行。此類惡意程式碼可以執行各種邪惡活動,例如將使用者重新導向到網路釣魚網站、竊取敏感資訊,甚至進一步傳播惡意軟體。就瀏覽器安全性而言,此類 XSS 漏洞是最嚴重的後果。 Snyk 如何偵測 CDN 上易受攻擊的 JavaScript 函式庫? --- 除了偵測專案清單和專案依賴項中的不安全程式碼和易受攻擊的第三方程式庫之外, [Snyk VS Code 擴充功能](https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner)還支援偵測使用靜態腳本匯入語句匯入的易受攻擊的程式庫。 例如,如果從 CDN 匯入的`lodash`庫使用易受攻擊的版本範圍或已知包含惡意程式碼,Snyk 將附加內聯註釋,以引起開發人員對安全風險的注意。 ![](https://res.cloudinary.com/snyk/image/upload/v1719411274/blog-polyfill-supply-chain-attack.png) 防範 CDN 供應鏈攻擊 --- 最近對 JavaScript polyfill 專案的攻擊凸顯了支援整個 Web 生態系統資源的至關重要性,而 CDN 是其中的重要組成部分。供應鏈安全問題通常圍繞著 PyPI 和 npm 等開源套件註冊中心,但 JavaScript polyfill 攻擊提醒我們,CDN 也是一個令人難以置信的網路建構塊。 以下是您應該考慮的一些最佳實踐,以幫助防範此類攻擊: - 使用受信任的 CDN:僅使用來自信譽良好的提供者的 CDN。例如,Cloudflare 以其強大的安全措施和可靠性而聞名。 - 監控依賴關係:定期審核和監控所有第三方腳本和依賴關係。 - 子資源完整性:子資源完整性 (SRI) 等工具可以幫助確保 CDN 交付的內容不被篡改,並且可以固定到經過審核且已知不存在惡意或其他不良行為的預期版本/雜湊。 - 內容安全策略 (CSP):實作強大的 CSP 以限制可以載入腳本的來源。這可以防止惡意腳本被執行。由於 Polyfill 通常包含在應用程式載入的關鍵路徑中,因此它們以與頁面上任何其他 JavaScript 相同的權限執行,這使得它們成為旨在利用這種信任的攻擊者的主要目標。這種風險凸顯了使用安全且信譽良好的 CDN、實施內容安全策略 (CSP) 等強大的安全措施以及定期審核第三方依賴項以防範此類漏洞的重要性。 - 定期更新:使所有庫和依賴項保持最新。許多攻擊利用了已在後續版本中修補的已知漏洞。 - 替代解決方案:評估您的專案是否仍需要 Polyfill。隨著瀏覽器的現代化,polyfill 提供的許多功能現在都得到了原生支援。高度考慮使用您自己的專案資產來供應依賴項,而不是依賴 CDN 等第三方提供者。 --- 原文出處:https://dev.to/snyk/polyfill-supply-chain-attack-embeds-malware-in-javascript-cdn-assets-55d6

了解 API:10 個 API 概念和範例

作為開發人員或技術人員,您可能聽說過“API”。聽到這個術語可能會讓您感到好奇。 本文將透過解釋可應用於 API 開發週期的基本概念和實踐來闡明 API。在開始使用 API 之前,您應該了解以下一件事 😂👇: ![一個人不嘗試模因](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8lzw28oxegw3hewvp8q.jpg) --- [⭐️ 您會考慮在 GitHub 上給我們一顆星嗎? ⭐️](https://github.com/latitude-dev/latitude) --- 您將從本文中學到什麼? ----------- - 對 API、其關鍵概念及其在開發週期中的重要性的基本了解。 - API 的類型及其基礎知識。 - API開發的最佳實踐 - 您可以在其中試驗 API 的工具或平台。 介紹 -- API 是現代開發的基本組成部分之一。它們支援應用程式和資料之間的無縫互動。使用 API 無需手動提供應用程式和資料之間的通信,而是使開發人員可以輕鬆且有效率地進行這種互動。 無論您是建立 Web 應用程式、行動應用程式還是整合服務,API 對於允許應用程式中的不同元件與資料無縫連接都至關重要。 什麼是 API? -------- API(應用程式介面)是一個由一系列命令、函數和協定組成的框架,可實現不同應用程式之間的互動。其主要目的是定義開發人員可以用來與其軟體元件互動的方法和資料結構。 將 API 想像成餐廳的服務生;你告訴服務員(API)你想要什麼,他們把它帶到廚房(伺服器),然後將你的食物(資料)傳回給你。這就是它的工作原理! ![伺服器迷因](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azkmbkvkjlurhs1u8ow0.jpg) API 可作為從應用程式取得請求、從伺服器取得必要資料,然後將處理後的資料傳回應用程式的連結。 API 類型 ------ 有針對不同用例和目的自訂的不同類型的 API。了解 API 類型有助於開發人員根據其特定需求選擇正確的 API。以下是最常見的 API 類型: - **公共或開放 API** :這些 API 向任何開發人員公開提供,幾乎沒有任何限制,使開發人員能夠存取服務的資料和功能。 ``` A good example of a place where you can get a public API is the [Some Random API platform](https://some-random-api.ml/). You will find a lot of API endpoints you can use freely in that service. ``` - **內部或私有 API** :它們的主要目的是團隊協作。它們通常不向外部開發人員開放,用於整合團隊或組織內的系統和服務。它們僅限於有權使用 API 的開發人員。 ``` APIs are made private for many reasons. Some are made private to secure sensitive data, accelerate development for business reasons, or enhance internal workflows. If you're working on a large-scale application, it's best to protect your API by privatizing it. ``` - **合作夥伴 API** :這是私有 API 的範例;它們不對公眾開放。然而,它們是專門為外部合作夥伴使用而設計的。存取權限通常是透過合約協議授予的,允許合作夥伴整合和存取某些功能或資料。 現在您已經了解了 API 的主要類型,最好了解它們的應用方式和位置。不同類型的 API 有不同的用途,並且最適合某些特定的專案。 REST API -------- **REST** (表述性狀態傳輸)或**RESTful** API 是建立 Web 應用程式並與之互動的規則。它們依靠標準 HTTP 方法和協定來實現客戶端和伺服器之間的通訊。 REST API 設計簡單、可擴展且無狀態,這使得它們在 Web 和行動應用程式中很受歡迎。與典型的 API 不同,RESTful API 不是協定;而是協定。相反,他們利用它們進行互動。 ![海綿寶寶表情包](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqvr2kaj2zj9b09micj2.jpg) 當客戶端請求時,伺服器會回應請求的資料。就是這麼簡單! REST API 原理 ----------- 一些架構原則指導 RESTful API;他們獨特的架構構成了一切,確保它們保持高效且易於使用。以下是 REST API 的一些獨特原則: - **無狀態性**:從客戶端到伺服器的每個請求都必須包含瞭解和處理請求的所有必要資訊。伺服器不儲存有關客戶端的任何會話狀態。 ``` This helps to simplify the server's architecture, as it doesn't need to manage and store session information, making the application more scalable. It also helps to give accurate information. ``` - **客戶端-伺服器架構**:在 REST API 中,客戶端和伺服器是透過請求和回應進行互動的獨立元件。客戶端處理使用者介面和使用者體驗,而伺服器管理資料儲存。 - **統一介面**:REST API 遵循一致的方式來存取資源。這包括使用`GET` 、 `POST` 、 `PUT`和`DELETE`等 HTTP 方法到 URI(統一資源辨識碼)來存取和操作資源。這使得 REST API 更容易理解和存取,因為開發人員可以依賴他們熟悉的模式。 - **可緩存性**:這是大多數開發人員喜歡的 RESTful API 的原則之一。使用 REST API,來自伺服器的回應被標記為可快取或不可快取。快取可以減少客戶端與伺服器互動的次數並提高效能。 ``` This increases efficiency by reducing unnecessary network calls, decreasing latency, and improving overall performance. ``` RESTful API 具有出色的結構,常用於現代開發週期。它的主要特點是它的原則,正是這些原則使得 REST API 成為現實。 ![騎自行車休息 api meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gp8lrzhnn5et5ae2cbqo.jpeg) 圖片來源:[菲爾·斯特金](https://x.com/philsturgeon/status/1047527475931041792) SOAP API -------- **SOAP** (簡單物件存取協定)API 是一種用於在 Web 應用程式中交換結構化資訊的協定。與使用簡單 HTTP 方法的 REST 不同,SOAP 利用 XML 作為訊息格式並遵循更複雜的結構。 SOAP API嚴格用於Web應用程式,並且內建命令來確保訊息的安全性,使其適合安全性嚴格的應用程式。 ### REST 和 SOAP 之間的差異 如同上面的定義所示, **REST**和**SOAP**之間有明顯的差異。雖然兩者都用於網絡,但它們在架構、標準等方面仍然存在差異。 - **協定VS架構風格**: ``` * **SOAP**: A protocol with standards and rules. ``` ``` * **REST**: An architectural style that uses standard HTTP methods and protocols for interaction between web applications and data. ``` - **訊息格式**: ``` * **SOAP**: Uses XML for message formatting. ``` ``` * **REST**: Uses JSON but can also use XML, HTML, or plain text for message formatting. ``` - **複雜性**: ``` * **SOAP**: It's more complex due to its standards and XML messaging. ``` ``` * **REST**: Simpler and more flexible, easier to implement. ``` - **運輸**: ``` * **SOAP**: Can use various protocols (HTTP, SMTP, etc.). ``` ``` * **REST**: Typically uses HTTPS for communication. ``` ![吃醋的女友表情包](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wb7524l1kjcwwh7qxgv.jpeg) 透過了解該協定和架構風格之間的差異,開發人員可以根據自己特定應用的需求選擇合適的協定。 JSON 和 XML ---------- **JSON(JavaScript 物件表示法)**和**XML(可擴充標記語言)**是標準的 API 通訊資料格式。這些格式具有相同的主要目的:對伺服器和客戶端之間的資料結構進行編碼,以便雙方都能理解。 ### JSON **JSON**是一種源自 JavaScript 的輕量級資料交換格式。它易於人類閱讀和編寫,也易於機器解析和生成。 ### XML **XML**是一種標記語言,它定義了以人類和機器可讀的格式對文件進行編碼的結構。 XML 主要以其處理複雜資料結構的能力而聞名。 ### JSON 和 XML 之間的差異 - **可讀性**: ``` * **JSON**: Syntax is more readable, ideal for quick interaction, and more accessible for developers. ``` ``` * **XML**: Comes with a more complex syntax. Best tailored for representing complex data structures and documents. ``` - **尺寸**: ``` * **JSON**: More compact and lightweight. Results in faster data transmission and less bandwidth usage. ``` ``` * **XML**: Larger due to extensive use of markdown tags. ``` - **資料類型**: ``` * **JSON**: Supports data types such as strings, numbers, arrays, and objects. ``` ``` * **XML**: All data is written in text, requiring parsing for specific data types. ``` - **解析和效能**: ``` * **JSON**: Faster to parse, especially in JavaScript environments, due to compatibility. ``` ``` * **XML**: Slower to parse and process, requiring more resources. ``` - **架構支援**: ``` * **JSON**: JSON schema is available but not as extensive as XML schema. ``` ``` * **XML**: XML schema is very powerful for verifying document structure and data types. ``` 使用 API 時,您可以使用任何所需的資料格式進行通訊。最好了解其差異,因為在 API 開發中不存在可使用的「完美」資料格式。您可以根據您的需求選擇其中任何一個。 ### 何時使用 有些情況下您可以使用 JSON 作為資料格式,有些情況下您可以使用 XML。知道何時何地使用它們非常重要。 您可以在以下情況下使用**JSON** : - 您需要一種輕量級的資料格式。 - 使用 Web API,尤其是在 JavaScript 環境中。 - 簡單性和可讀性至關重要。 - 您正在處理更簡單的資料結構,並且需要減少頻寬使用。 您可以在以下情況下使用**XML** : - 您想要處理複雜的資料結構。 - 需要驗證資料格式和結構。 - 使用需要大量元資料和描述性資料的應用程式。 - 資料交換需要具有高度可擴展性和自描述性。 透過了解同時使用 JSON 和 XML 的優點和案例,開發人員可以根據應用程式的需求決定使用哪種資料格式。 API端點 ----- 在本文中,您可能想知道 API 端點是什麼,因為您可能在本文中多次遇到術語「API 端點」。 **API 端點**是一個 URL,用戶端可以透過該 URL 存取 API 以執行檢索、更新或刪除資料等操作。端點代表 API 提供的功能和服務。 端點允許 API 與您正在處理的應用程式進行交互,從而實現通訊和資訊交換。它們可以透過 HTTP 方法存取,例如`GET` 、 `POST` 、 `PUT`和`DELETE` ,這些方法定義了將執行的操作類型。 ### API 端點範例 讓我們考慮一個用於在 Web 應用程式中管理學生資訊的 REST API 範例。 API 的基本 URL 可以是[`https://api.example.com`](https://api.example.com) 。現在,讓我們來看看其他端點和回應。 - **檢索學生列表**: ``` * **Endpoint**: [https://api.example.com/students](https://api.example.com/students) ``` ``` * **HTTP method**: GET ``` ``` * **Purpose**: To retrieve a list of all registered students in the system. ``` ``` * **Request**: ``` ``` GET https://api.example.com/students ``` ``` Here is the response you get: ``` ``` [ { "id": 1, "name": "Opemipo Disu", "email": "[email protected]" }, { "id": 2, "name": "Ralf Endrick", "email": "[email protected]" } ] ``` ``` In this example, we used the GET method to retrieve information from the system. After that, it gives us the data we requested from the endpoint in JSON format. ``` 另一個例子可能是在系統中註冊學生的端點。讓我們建立它並查看它的響應。 - **新增新學生**: ``` * **Endpoint**: [https://api.example.com/students](https://api.example.com/students) ``` ``` * **HTTP Method**: POST ``` ``` * **Purpose**: Adding a new student to the management system. ``` ``` * **Request**: ``` ``` POST https://api.example.com/students Content-Type: application/json { "name": "Opemipo Disu", "email": "[email protected]" } ``` ``` **Response**: ``` ``` { "id": 1, "name": "Opemipo Disu", "email": "[email protected]" } ``` ``` In this case, you will notice we are working with the [https://api.example.com/students](https://api.example.com/students) endpoint, basically because we want to add a new student to the system; the only way the users could be accessed is by using that endpoint because it should have information related to the student in it. ``` 現在,讓我們考慮刪除特定學生的資訊。我們可以這樣做: - **刪除學生訊息** ``` - **Endpoint**: [**https://api.example.com/students/{id}**](https://api.example.com/students/%7Bid%7D) ``` ``` - **HTTP method**: DELETE ``` ``` - **Purpose**: To delete a student by their ID. ``` ``` - **Request**: ``` ``` DELETE https://api.example.com/students/1 ``` ``` **Response**: ``` ``` { "message": "Student deleted successfully." } ``` ``` When you want to delete a student's information using an API, addressing the specific data by its ID in the API endpoint ensures that you target the correct record. ``` 透過了解端點的工作原理並查看一些範例,開發人員還可以使用 API 與 Web 應用程式互動並執行各種操作。 **HTTP 方法** ----------- HTTP 方法定義對 API 端點辨識的資源執行的操作。我們有近 40 個已註冊的 HTTP 方法,但以下是四個最常見的方法: - 得到 - 郵政 - 放 - 刪除 現在,我們將探討這些方法的用途,並為四種最常用的 HTTP 方法分別提供一個範例。 ### **得到** **GET**方法從伺服器檢索資料,而不對伺服器資料進行任何更改。 前面在用於檢索學生資訊的端點中展示了其工作原理的範例。 再舉個例子: **要求**: ``` GET https://api.example.com/students ``` **回覆**: ``` [ { "id": 1, "name": "Opemipo Disu", "email": "[email protected]" }, { "id": 2, "name": "Ralf Endrick", "email": "[email protected]" } ] ``` 如上所示,GET 方法用於從端點檢索以 JSON 格式顯示的資料。 ### **郵政** **POST**方法將資料傳送到伺服器以建立新資源。與用於檢索資料的 GET 不同,POST 向伺服器提交資料。 GET 依賴透過 POST 傳送到伺服器的資料。 前面已經解釋瞭如何使用 POST 方法的範例。學生的註冊範例就是一個可以使用 POST 方法的精確實例。 如果您錯過了,請再看一遍。 **要求**: ``` POST https://api.example.com/students Content-Type: application/json { "name": "Opemipo Disu", "email": "[email protected]" } ``` 我們使用 POST 方法發送請求。使用它是因為我們想將學生的資訊加入到伺服器。 這是我們這樣做得到的回應: ``` { "id": 1, "name": "Opemipo Disu", "email": "[email protected]" } ``` 在上面的回應中,POST 方法會自動幫助建立和註冊新學生。這就是 POST 方法的工作原理。 ### **放** 此方法用於使用新資料更新現有資源,或建立新資源(如果不存在)。它將資源的當前資訊替換為請求中提供的資料。 我們來看一個使用 PUT 方法更新學生資訊的範例。 **要求**: ``` PUT https://api.example.com/students/1 Content-Type: application/json { "name": "Opemipo Hay", "email": "[email protected]" } ``` **回覆**: ``` { "id": 1, "name": "Opemipo Hay", "email": "[email protected]" } ``` 在這種情況下,我們必須使用其 ID 來找到我們想要更新的資訊。我們使用 PUT 方法並加入了我們想要更新的資料。 ### **刪除** 此方法用於刪除現有資源。當發出 DELETE 請求時,伺服器會刪除 URI 標識的資源。 為此,我們以透過學生ID刪除學生資訊為例。 **要求**: ``` DELETE https://api.example.com/students/1 ``` **回覆**: ``` { "message": "Student's information deleted successfully" } ``` 在請求中,我們使用 DELETE 方法根據使用者的 ID 刪除使用者的資訊。之後,我們收到回應:“學生資訊刪除成功。” **HTTP 狀態碼** ------------ HTTP 狀態碼是伺服器傳回的回應,用於指示客戶端請求的結果。它們透過向伺服器顯示客戶端請求的結果,在 API 通訊中發揮著至關重要的作用。 以下是許多 HTTP 狀態碼中的一些常見內容: - 200 - 400 - 500 ### **200(還可以)** 當收到此回應時,說明請求成功,伺服器傳回請求的資料。 您可以獲得此回應的一個範例是當存在成功檢索資料的 GET 請求時。這在**開發者控制台**的**網路**標籤中表明操作已成功並且伺服器按預期處理了請求。 ### **400(未找到)** 當伺服器找不到所要求的資源或資料時,您會收到此回應。這可能是因為未正確取得資料或資源不存在。 當您對不存在的使用者使用`GET`請求時,可能會發生此錯誤。讓我們快速瀏覽一下: **要求**: ``` GET https://api.example.com/users/583 ``` **回覆**: ``` { "status": 404, "message": "Resource not found" } ``` 回應給出錯誤,因為假定端點中沒有資源。 ![複製答案表情包](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3u35kypk3g7hmhu4is63.jpeg) ### 500內部伺服器錯誤) 當您收到此回應時,伺服器遇到了意外情況,導致其無法滿足請求。 當處理請求時發生伺服器端錯誤時,您可能會收到此回應。 **要求**: ``` POST https://api.example.com/students Content-Type: application/json { "name": "Opemipo", "email": "[email protected]" } ``` **回覆**: ``` { "status": 500, "message": "Internal server error" } ``` **500 內部伺服器錯誤**表示一般伺服器端錯誤。它表明伺服器上出現了問題,不一定是由於客戶端的請求造成的。 雖然還有一些其他 HTTP 狀態程式碼,但[您可以閱讀本文以了解有關它們的更多資訊](https://www.geeksforgeeks.org/10-most-common-http-status-codes/)。本文提供的是最常見的狀態程式碼。 **認證與授權** --------- 雖然 API 安全至關重要,但身分驗證和授權是 API 安全的關鍵組成部分。 API 開發中的驗證是驗證使用者或應用程式身分的過程,通常透過 API 金鑰、OAuth 令牌或使用者憑證等技術。 另一方面,授權確定允許經過身份驗證的實體存取哪些資源或操作。 這些流程確保只有有效的使用者或應用程式才能存取 API 並根據其權限執行操作。 ### API 金鑰和 OAuth 的基本概念 **API 金鑰**是用於驗證與專案或應用程式關聯的請求的唯一辨識碼。 API 金鑰包含在 API 請求中,用於辨識呼叫專案或應用程式。它們通常用於追蹤和控制 API 的使用方式。 API 金鑰應保持安全,不得在程式碼中公開,以防止未經授權的存取。 但是,它們並不安全,應與其他安全措施(例如環境變數)一起使用。 另一方面, **OAuth** (開放授權)是一種基於令牌的身份驗證框架,允許第三方應用程式在不暴露使用者憑證的情況下存取使用者資料。 它被 Google 和 GitHub 等平台廣泛使用,以授予對用戶資料的有限存取權。它涉及使用者授權應用程式的流程,並且應用程式接收可用於發出授權 API 請求的存取權杖。與 API 金鑰相比,它提供了更靈活、更安全的方法。 ### API 安全的重要性 - **防止未經授權的存取**:身份驗證可確保只有使用者和應用程式才能存取 API,從而防止未經授權存取敏感資料。 - **速率限制**:身份驗證有助於追蹤 API 的使用情況,從而實現速率限制以防止資料濫用。 - **監控**:身份驗證允許詳細記錄和監控 API 使用情況,這對於辨識錯誤至關重要。 速率限制和節流 ------- API 使用速率限制來維持穩定和安全。這意味著它們限制使用者或應用程式在一定時間內可以發出的請求數量。這有助於防止伺服器過載。 它還確保應用程式中的所有使用者都能平等分配 API 資源。 為了管理速率限制,如果達到限制,應用程式應逐漸增加重試之間的等待時間。監控您的 API 使用情況以保持在這些限制之內。如果您儲存常用資料,則可以減少發出的請求數量。 使用頁碼和過濾器可以幫助您更快地管理大型資料集,從而減少 API 的負載。 **測試 API** ---------- 測試 API 在 API 開發過程中至關重要,以確保您的應用程式與伺服器正確通訊並按預期處理資料。專用工具可讓您在開發週期的早期發出 API 請求、檢查和分析回應並記錄問題。 讓我們探索一些用於測試 API 的最佳工具,並提供有關使用這些工具有效測試 API 的基本指南。 ### API測試工具 - [**Postman**](https://www.postman.com/) **:** Postman是一個簡化API開發的工具。它允許您建立和發送請求、將 API 組織到集合中、自動化測試並產生詳細報告。 ``` Ideal for both manual and automated testing, Postman supports various HTTP methods, making it flexible for testing. ``` - [cURL](https://curl.se/) **:**此命令列技術支援使用 URL 進行資料傳輸。 ``` cURL is used mainly because of its accessibility and flexibility, especially for developers comfortable with the command line. ``` - [**Swagger**](https://swagger.io/) **:** Swagger 提供了一套用於 API 文件和測試的工具。它允許您可視化 API 的資源並與之交互,而無需手動建立請求。 ### **有關如何測試 API 的指南** 1. **定義端點和方法** ``` - Determine the API endpoint you wish to test and the HTTP method (GET, POST, PUT, DELETE) to use. ``` ``` - Example: To fetch user data, you might use: ``` ``` GET https://api.example.com/users ``` 2. **設定請求** ``` - **Postman**: Open Postman, create a new request, enter the endpoint URL, and select the HTTP method. Add necessary headers like API keys and parameters. ``` ``` For a GET request to retrieve users, just set the URL to [**`https://api.example.com/users`**](https://api.example.com/users) and include any required headers or parameters. ``` 3. **發送請求** ``` - Click "**Send**" in Postman to execute the request and observe the response. ``` 4. **分析回應** ``` - **Status Code**: Indicates the success or failure of the request (e.g., 200 OK, 404 Not Found). ``` ``` - **Headers**: Provide metadata about the response. ``` ``` - **Body**: Contains the data returned by the API, typically in JSON or XML format. ``` ``` - **Example**: A successful GET request might return a status code 200 and a JSON body with user data. ``` 5. **處理錯誤** ``` - If the request fails, analyze the status code and error message to diagnose the issue. ``` ``` - **Example**: A **404 status code** indicates that the endpoint is incorrect or the resource does not exist. ``` ``` - Adjust the request accordingly and retry. ``` 6. **自動化測試** ``` - Postman supports scripting to automate tests. You can write pre-request scripts to set conditions and test scripts to validate responses. ``` ``` - **Example**: To verify a successful response, add the following script in Postman's "Tests" tab: ``` ``` pm.test("Status code is 200", function () { pm.response.to.have.status(200); }); ``` 透過利用 Postman、cURL 和 Swagger 等工具,您可以簡化 API 測試流程,確保您的應用程式可靠且有效率地與外部服務互動。 **結論** ------ 了解 API 對於任何剛起步的開發人員來說都是至關重要的。它們是現代開發的主要組成部分,可實現應用程式之間的無縫通訊和資料交換。 本文介紹了 API 的基本概念,包括它們的類型、REST 和 SOAP API 的關鍵原理、JSON 和 XML 等資料格式,以及 API 端點和 HTTP 方法的重要性。 此外,我們也透過身分驗證和授權探討了 API 安全性的各個方面,以及速率限制和限制的重要性。 如果您覺得這篇文章有幫助,請考慮在 GitHub 上給我們一顆星 [⭐ 您可以考慮在 GitHub 上給我們一個 Star 嗎?](https://github.com/latitude-dev/latitude) ![謝謝你](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an3sgmfqrn9p5s07a6dj.gif) 您的支持有助於我們繼續改進並向開發者社群提供有價值的內容。感謝您閱讀本文到目前為止! --- 原文出處:https://dev.to/latitude/understanding-apis-10-api-concepts-and-examples-23cn

掌握堅實的原則 ✅

SOLID 原則是物件導向程式設計中的設計原則,可協助開發人員建立更易於理解、靈活且可維護的軟體。 讓我們深入研究每個原則,看看如何使用 JavaScript 應用它們。 --- 📌 1.單一職責原則(SRP) --------------- **定義:**一個類別應該只有一個改變的理由,這意味著它應該只有一項工作或責任。 ``` class User { constructor(name, email) { this.name = name; this.email = email; } } class UserService { createUser(user) { // logic to create user } getUser(id) { // logic to get user } } class UserNotificationService { sendWelcomeEmail(user) { // logic to send email } } const user = new User('John Doe', '[email protected]'); const userService = new UserService(); userService.createUser(user); const notificationService = new UserNotificationService(); notificationService.sendWelcomeEmail(user); ``` 這裡, `User`處理使用者資料, `UserService`處理與使用者相關的操作, `UserNotificationService`處理通知。每個類別都有一個職責。 --- 📌2.開閉原則(OCP) ------------ **定義:**軟體實體應該對擴充開放,但對修改關閉。 ``` class Rectangle { constructor(width, height) { this.width = width; this.height = height; } area() { return this.width * this.height; } } class Circle { constructor(radius) { this.radius = radius; } area() { return Math.PI * Math.pow(this.radius, 2); } } const shapes = [new Rectangle(4, 5), new Circle(3)]; const totalArea = shapes.reduce((sum, shape) => sum + shape.area(), 0); console.log(totalArea); ``` 在此範例中,可以擴展每個形狀類別的`area`方法(如`Rectangle`和`Circle` ),而無需修改形狀類別的現有程式碼。這允許將來加入新形狀而無需更改現有形狀。 --- 📌 3.里氏替換原理(LSP) --------------- **定義:**子類型必須可以替換其基底類型,而不改變程式的正確性。 ``` class Bird { fly() { console.log('I can fly'); } } class Duck extends Bird {} class Ostrich extends Bird { fly() { throw new Error('I cannot fly'); } } function makeBirdFly(bird) { bird.fly(); } const duck = new Duck(); makeBirdFly(duck); // Works fine const ostrich = new Ostrich(); makeBirdFly(ostrich); // Throws error ``` 在此範例中, `Ostrich`違反了 LSP,因為它改變了`fly`方法的預期行為。為了遵守LSP,我們應該確保子類別不會改變基底類別所期望的行為。 --- 📌 4.介面隔離原則(ISP) --------------- **定義:**不應強迫客戶端依賴他們不使用的介面。 ``` class Printer { print() { console.log('Printing document'); } } class Scanner { scan() { console.log('Scanning document'); } } class MultiFunctionPrinter { print() { console.log('Printing document'); } scan() { console.log('Scanning document'); } } const printer = new Printer(); printer.print(); const scanner = new Scanner(); scanner.scan(); const multiFunctionPrinter = new MultiFunctionPrinter(); multiFunctionPrinter.print(); multiFunctionPrinter.scan(); ``` 在這裡, `Printer`和`Scanner`類別提供特定的功能,而不強迫客戶端實作他們不需要的方法。 `MultiFunctionPrinter`可以使用這兩種功能,並遵守 ISP。 --- 📌5.依賴倒置原則(DIP) -------------- **定義:**高層模組不應該依賴低層模組。兩者都應該依賴抽象。抽像不應該依賴細節。細節應該取決於抽象。 ``` class NotificationService { constructor(sender) { this.sender = sender; } sendNotification(message) { this.sender.send(message); } } class EmailSender { send(message) { console.log(`Sending email: ${message}`); } } class SMSSender { send(message) { console.log(`Sending SMS: ${message}`); } } const emailSender = new EmailSender(); const notificationService = new NotificationService(emailSender); notificationService.sendNotification('Hello via Email'); const smsSender = new SMSSender(); const notificationServiceWithSMS = new NotificationService(smsSender); notificationServiceWithSMS.sendNotification('Hello via SMS'); ``` 在此範例中, `NotificationService`依賴抽象( `sender` ),允許它與任何發送者實作(如`EmailSender`或`SMSSender` )一起使用。這透過使高階模組 ( `NotificationService` ) 依賴抽象而非具體實作來遵守 DIP。 --- --- 結論✅ --- 透過遵循 SOLID 原則,您可以設計出更健壯、可維護和可擴展的 JavaScript 應用程式。 這些原則有助於確保您的程式碼庫保持乾淨和靈活,從而隨著應用程式的成長更容易管理和擴展。 一致地應用這些原則可以顯著提高軟體的品質。 --- ***快樂編碼!*** 🔥 **[LinkedIn](https://www.linkedin.com/in/dev-alisamir)** 、 **[X (Twitter)](https://twitter.com/dev_alisamir)** 、 **[Telegram](https://t.me/the_developer_guide)** 、 **[YouTube](https://www.youtube.com/@DevGuideAcademy)** 、 **[Discord](https://discord.gg/s37uutmxT2)** 、 **[Facebook](https://www.facebook.com/alisamir.dev)** 、 **[Instagram](https://www.instagram.com/alisamir.dev)** --- 原文出處:https://dev.to/alisamirali/mastering-solid-principles-1aa6

比披薩更吸引開發者的 12 個開源工具👋🍕

現在是開源工具時間! 除了大家都知道的前 3 個之外,開源工具還有更多內容。 哎呀,你實際上可能已經知道這個清單中的所有 12 個(在這種情況下:「慢拍」),但我們大多數人都不知道。 ![開發者開源慢拍手](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87r8u8xpfavjuc4xp96v.gif) 當談到幫助開發人員完成工作的工具時,開源是一個令人信服的論點! 這就是為什麼我們也推出了自己的[開源工具來提高開發人員的生產力。](https://github.com/middlewarehq/middleware) 因此,這裡列出了 12 個開源工具,它們可能成為您的工具包中不可或缺的一部分。 我們走吧! > 注意:我們發現專案中存在一些不一致之處,根據社區的建議重新表述並加入了新專案。 1.Theia ----- 當您正在尋找 VSCode 的[真正開源替代品](https://eclipse-foundation.blog/2020/05/05/eclipse-theia-and-vs-code-differences-explained/)時,請考慮 Theia。 它是一個靈活的 IDE,可在雲端和桌面上執行。它是用 TypeScript 建構的,並附帶許多可供您使用的附加元件。 - **主要特徵**: - 雲端和桌面 IDE 功能 - 可擴展的插件系統:接受 VSCode 插件/擴展 - 多語言支援 - [忒亞網站](https://theia-ide.org/) - [忒亞 Github](https://github.com/eclipse-theia/theia) 2.Postman ---- 我們很多人都知道 Postman。 不不,不是給你的亞馬遜包裹送貨的人。 ![郵差開源](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2pslqrzp72ztaf3myck.gif) 此 Postman 讓您可以將請求連結在一起、自動執行任務以及與其他人協作,從而更輕鬆地使用 API。 因此,如果您不喜歡 cURL,Postman 可以拯救您。 - **主要特徵**: - API測試和自動化 - 複雜工作流程的請求鏈 - 團隊協作工具 - [郵差網站](https://www.postman.com/) - [郵差Github](https://github.com/postmanlabs/postman-app-support) 3. Hoppscotch ------ Hoppscotch 是一個免費、輕量級、快速且漂亮的 API 請求建立器工具,可以相對快速地建立和測試您的 API。 - **主要特徵**: - HTTP 請求方法(GET、POST、PUT、DELETE、PATCH 等) - 對 GraphQL 的內建支持 - 集合管理與環境變數 - **網站**:[跳房子](https://hoppscotch.io/) - **GitHub** :[跳房子 GitHub](https://github.com/hoppscotch/hoppscotch) 4. Pocketbase ------- Pocketbase 是一個檔案中的開源即時後端,可在 Flutter、Vue、React 和 Angular 應用程式中使用。 想像一下用 Go 編寫的為開發人員提供的簡單的 SQL 資料庫。 - **主要特徵**: - 具有即時訂閱功能的嵌入式資料庫 (SQLite) - 內建文件和使用者管理 - 以及簡單的 REST-ish API - [Pocketbase網站](https://pocketbase.io/) - [Pocketbase Github](https://github.com/pocketbase/pocketbase) 5. cURL ----- 我想沒有一個開發人員不知道 cURL。 cURL 是一個簡單的命令列工具,用於呼叫 API。事實上,大多數作業系統發行版(例如 Linux 和 MacOS)中都預設包含 cURL。 - **主要特徵**: - 支援多種協定(HTTP、FTP等) - 可編寫腳本的命令列工具 - [捲曲網站](https://curl.se/) - [捲曲Github](https://github.com/curl/curl) 6. Waveterm ----- Waveterm 是一款開源 AI 原生終端機。 Waveterm 將命令列與開放網路連結起來,幫助開發人員提高工作效率。 - **主要特徵**: - 跨網路斷開和重新啟動的持久會話 - 可搜尋的上下文命令歷史記錄 - CodeEdit,使用類似 VSCode 的內聯編輯器編輯本機和遠端文件 - AI 與 ChatGPT(或 ChatGPT 相容 API)集成,幫助編寫命令並獲得內聯答案 - [Waveterm 網站](https://www.waveterm.dev/) - [Waveterm Github](https://github.com/wavetermdev/waveterm) 7. Ollama ----- AI 風靡一時,到 2024 年,不與當地 LLM 打交道的開發人員根本就不是開發人員,對嗎? Ollama 致力於在本地試驗大型語言模式。 它就像法學碩士的 Docker Desktop。 ![奧拉馬開源](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8l3mt8lhulrm4iftjjtz.gif) - **主要特徵**: - 法學碩士的本地實驗 - 大語言模型的開發環境 - OpenAI 相容 API - [奧拉馬網站](https://ollama.com/) - [奧拉馬 Github](https://github.com/ollama/ollama) 8.LM-Studio ------- LM-Studio 也類似 Docker Desktop,是 Ollama 的競爭對手。 - **主要特徵**: - 法學碩士的本地實驗 - OpenAI 相容 API - 支援 Windows 電腦 - [LM-Studio 網站](https://lmstudio.ai/) - [LM-Studio Github](https://github.com/lmstudio-ai) 9.VS Code ------ 告訴我您知道 VS Code 是開源的。請告訴我。 VS Code 或多或少是當今大多數開發人員開始使用的第一個程式碼編輯器。除非你在 Linux 上使用 Vim。順便說一句,我使用 Arch。 VSCode 的擴展數量之多難以想。 - **主要特徵**: - 可擴展的程式碼編輯器 - 除錯支援 - 豐富的擴展生態系統 - [VS 程式碼網站](https://code.visualstudio.com/) - [VS 程式碼 Github](https://github.com/microsoft/vscode) 10.Docker Compose ------------ 現在每個人都使用 Docker,對嗎? Docker Compose 可以透過使用簡單的`compose.yaml`檔案更輕鬆地設定多個連接的 Docker 應用程式。 - **主要特徵**: - Docker容器的編排 - 使用 YAML 定義服務 - 多容器應用程式管理 - [Docker 撰寫網站](https://docs.docker.com/compose/) - [Docker 組合 Github](https://github.com/docker/compose) 11.ESLint --------- ESLint 是一款適用於 JavaScript 和 TypeScript 的出色工具,它透過可自訂的 linting 規則和外掛程式強制執行編碼標準並提高程式碼品質。 ESLint 與 Prettier 和其他此類工具結合可以幫助廣大 JavaScript 開發人員。 - **主要特徵**: - 程式碼品質分析 - 可設定的 linting 規則 - JavaScript 和 TypeScript 支持 - [ESLint 網站](https://eslint.org/) - [ESLint Github](https://github.com/eslint/eslint) 12. Oh My Zsh --------- Oh My Zsh 就像您的 Zsh shell 設定的超級升級,它有酷炫的主題和插件,可以讓您的終端體驗更上一層樓。 當然,對於某些人來說,取得合適的 Zsh 資源檔案往往有點困難。 - **主要特徵**: - Zsh設定管理 - 可自訂的主題和插件 - 社區驅動的發展 - [哦我的 Zsh 網站](https://ohmyz.sh/) - [哦我的 Zsh Github](https://github.com/ohmyzsh/ohmyzsh) --- 我錯過了一些重要的事情嗎? 你怎麼認為? https://github.com/middlewarehq/middleware --- 原文出處:https://dev.to/middleware/13-foss-tools-that-developers-would-give-up-pizza-for-4a6g

使用 ToolJet 建立 AI BPMN 圖分析器🛠️

在本教程中,我們將使用 ToolJet 建立一個 BPMN 圖分析器應用程式。該應用程式允許用戶透過以圖像格式上傳來產生 BPMN 流程的詳細說明。我們將使用**ToolJet 的低程式碼應用程式建構器**作為使用者介面及其**查詢建構器**來連接到 Gemini API,以產生對上傳的 BPMN 流程的深入分析。 以下是我們應用程式的快速預覽: ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/20b0iaftmp1hpm9bbae0.gif) 先決條件 ---- **Gemini API 金鑰**:Gemini API 是[Google AI Studio](https://aistudio.google.com/app/apikey)提供的進階 AI 服務。它使開發人員能夠將強大的內容生成功能整合到他們的應用程式中。 **ToolJet** (https://github.com/ToolJet/ToolJet):一個開源、低程式碼的商業應用程式建構器。[註冊](https://www.tooljet.com/signup)免費的 ToolJet 雲端帳號或使用 Docker[在本機上執行 ToolJet](https://docs.tooljet.com/docs/setup/try-tooljet/) 。 首先,建立一個名為*BPMN 圖分析器*的新應用程式。 --- 步驟 1: 新增 UI 元素🖼️ ---------------- 應用程式建置流程的第一步是利用 ToolJet 的可自訂預建置元件在幾分鐘內建立 UI。我們將從標題開始。 ### 應用程式標題 1. 對於徽標,在畫布頂部加入一個**Icon**元件並將其命名為`logo` 。 2. 選擇適當的圖示(例如`IconAnalyzeFilled` )並將其顏色設為`#3e63ddff` 。 3. 在圖示元件旁邊新增一個**文字**元件。 4. 將其資料屬性設定為“BPMN 圖分析器”。 5. 使用`#3e63ddff`作為顏色, `24px`作為字體大小,字體粗細為粗體。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1r4qz4lxsqiu65o61fae.png) *我們使用藍色(十六進位程式碼:#3e63ddff)作為主要顏色,相應地設計即將到來的元件。* ### 輸入部分 1. 在左側新增一個**Container**來儲存輸入元素,並將其命名為`inputContainer` 。 2. 在此容器內,新增一個**Text**元件作為標題,並將其命名為`inputLabel` 。 3. 將文字元件的資料屬性設定為“輸入”。 4. 在其下方放置一個**Image**元件來顯示上傳的 BPMN 圖。將其命名為`imagePreview` 。 5. 新增**檔案選擇器**元件並將其命名為`fileUploader` 。 6. 新增一個標記為「生成」的**按鈕**元件。將其命名為`generateButton` 。 7. 新增另一個標有「複製輸出」的**按鈕**,並將其命名為`copyButton` 。 8. 將按鈕放置在文件選擇器旁的適當位置。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jskct4n24vbg07jmv2oz.png) ### 輸出部分 1. 為輸出部分新增另一個**容器**,並將其命名為`outputContainer` 。 2. 在此容器內新增一個**Text**元件作為標題,並將其命名為`outputLabel` 。 3. 將文字元件的資料屬性設定為“輸出”。 4. 為產生的解釋加入另一個**文字**元件。將其命名為`generatedOutput` 。 5. 將資料格式設為 HTML,因為產生的解釋將採用 HTML 格式。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mjvytfj5sfdzsp8g7cdx.png) --- 第 2 步:設定查詢🔗 ----------- UI 準備好後,我們現在可以連接到 Gemini API 並使用查詢格式化映像預覽。 ### 產生圖像預覽查詢 1. 建立一個名為`generateImagePreview`的新**執行JavaScript程式碼**查詢。 2. 在查詢中加入以下程式碼: ``` return `data:image;base64,${components.fileUploader.file[0].base64Data}` ``` 上面的查詢將重構圖像資料並傳回它。傳回的值將用作 URL,以在 Image 元件中將圖像顯示為預覽。 ### 分析圖查詢 1. 建立一個名為`analyseDiagram`的新**REST API**查詢。 2. 將方法設為 POST 並在 URL 屬性下輸入以下 URL: ``` https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent ``` 3. 在**Headers**下,新增標頭並將鍵設為`Content-Type`並將值設為`application/json` 。 4. 建立一個名為`GEMINI_API_KEY`的新工作區常數,並在其中新增您的 Gemini API 金鑰。 5. 在**「Parameters」**下,新增一行,其中鍵為`key` ,值為`{{constants.GEMINI_API_KEY}}` 。 6. 使用以下程式碼配置查詢的 Body 屬性: ``` { "contents": [ { "parts": [ { "text": "Explain in depth the content and overall of the uploaded BPMN (Business Process Model and Notation) diagram in HTML formatting only. Respond with only the explanation, and nothing else. Return the following information, with clear bullet points and headers (under 18 px) for each section: 1. **Title**: The title or main heading of the BPMN diagram. 2. **Description**: A brief description or summary of the BPMN diagram. 3. **Elements**: Explain all the processes identified in the diagram in the correct flow. If there are multiple sequences, explain them individually. 4. **Flows**: Describe the sequence flows, message flows, and associations between elements. 5. **Data Objects**: Identify and describe any data objects present in the diagram. 6. **Swimlanes**: If present, list the swimlanes (e.g., pools, lanes) and their roles or participants. Ensure the returned HTML is well-structured, with appropriate tags for headers, lists, and any other necessary elements for readability and organization." }, { "inline_data": { "mime_type":"image/jpeg", "data": "{{components.fileUploader.file[0].base64Data}}" } } ] } ] } ``` 此 JSON 請求發送上傳的 BPMN 圖圖像進行分析,要求提供其內容的詳細 HTML 解釋,包括標題、描述、元素、流、資料物件和泳道。 --- 第三步:使用事件進行動態互動🔘 --------------- ToolJet 中的事件可讓您根據按鈕點擊或查詢完成等觸發器輕鬆建立動態應用程式互動。 ### 產生按鈕點擊 1. 將新事件新增至**「生成」**按鈕。 2. 將“事件”保留為**“單擊時”** ,選擇**“執行查詢”**作為“操作”,選擇“查詢”作為`analyseDiagram` 。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juagcv10qmhon1i8i8ac.png) 現在,每次按一下「產生」按鈕時,都會執行`analyseDiagram`查詢並產生輸出。 ### 複製按鈕點擊 1. 在**「複製輸出」**按鈕上新增按**一下**事件,以將產生的輸出複製到剪貼簿。 2. 將操作設定為**「複製到剪貼簿」** ,然後在「文字」屬性下輸入以下程式碼: ``` {{components.generatedOutput.text}} ``` ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jqovfgxi4tt882feg4oo.png) 每次我們點擊“複製輸出”按鈕時,上述設定都會從相關元件複製輸出文字。 ### 文件選擇器載入: 1. 在檔案選擇器元件上新增**檔案載入**事件以執行generateImagePreview 查詢。 2. 此配置將確保每次將檔案上傳到檔案選擇器元件時都會執行`generateImagePreview`查詢。 ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/84funu16nihb1wkh9xww.png) 此配置將確保每次將檔案上傳到檔案選擇器元件時都會執行generateImagePreview 查詢。 ### 圖像預覽 1. 在**Image**元件的 URL 屬性下,輸入以下程式碼: ``` {{queries.generateImagePreview.data}} ``` 現在,使用檔案選擇器上傳 BPMN 圖表圖像後,圖像元件將顯示該圖像。 --- 第 4 步:測試 ✅ ---------- 是時候測試所有功能了。 - 使用**檔案選擇器**上傳圖像 - 預覽應該在圖像元件上可見。 - 點選**「產生」按鈕**- 輸出中的「文字」元件應透過 HTML 格式顯示 BPMN 圖的深入解釋。 - 點擊**“複製輸出”按鈕**- 產生的解釋應該被複製,並且您應該收到一條通知,顯示“已複製到剪貼簿!” ![圖片描述](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/092pwp4qug1auw560d1q.png) --- 結論 -- 透過遵循本教學課程,您已使用 ToolJet 成功建立了 BPMN 圖分析器。該應用程式允許用戶上傳圖像格式的 BPMN 圖並接收詳細解釋,從而增強他們的工作流程分析能力。您可以根據您的具體要求隨意進一步擴展和自訂應用程式。快樂建設! 要了解和探索有關 ToolJet 的更多訊息,請查看[ToolJet 文件](https://docs.tooljet.com/docs/tooljet-concepts/what-are-components)或聯絡我們並在[Slack](https://tooljet.slack.com/)上發布您的問題。 --- 原文出處:https://dev.to/tooljet/build-an-ai-bpmn-diagram-analyzer-using-tooljet-2b00

🔧 進階 JavaScript 效能優化:技術與模式

隨著 JavaScript 應用程式變得越來越複雜,優化效能變得越來越重要。這篇文章深入探討了先進的技術和模式,以提高您的 JavaScript 效能並確保您的應用程式即使在重負載下也能順利執行。 🛠️記憶體管理 ------- 高效的記憶體管理是維持 JavaScript 應用程式效能的關鍵。糟糕的記憶體管理可能會導致洩漏和崩潰。 ### 提示:避免全域變數 盡量減少全域變數的使用,防止記憶體洩漏,確保更好的封裝。 ``` (function() { const localVariable = 'I am local'; console.log(localVariable); })(); ``` ### 提示:使用 WeakMap 進行緩存 WeakMap 允許您快取物件而不阻止垃圾收集。 ``` const cache = new WeakMap(); function process(data) { if (!cache.has(data)) { const result = expensiveComputation(data); cache.set(data, result); } return cache.get(data); } function expensiveComputation(data) { // Simulate expensive computation return data * 2; } ``` 🌐 用於離線快取的 Service Worker ------------------------ Service Worker 可以透過快取資產和啟用離線功能來顯著提高效能。 ### 提示:實施基本 Service Worker 設定 Service Worker 來快取資產。 ``` // sw.js self.addEventListener('install', event => { event.waitUntil( caches.open('v1').then(cache => { return cache.addAll([ '/index.html', '/styles.css', '/script.js', '/image.png' ]); }) ); }); self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(response => { return response || fetch(event.request); }) ); }); // Register the Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(() => console.log('Service Worker registered')) .catch(error => console.error('Service Worker registration failed', error)); } ``` 📊 用於效能密集型任務的 WebAssembly ------------------------ WebAssembly (Wasm) 是一種允許高效能程式碼執行的二進位指令格式。 ### 提示:使用 WebAssembly 進行繁重運算 將應用程式的效能關鍵部分編譯到 WebAssembly。 ``` // C code (example.c) #include <emscripten.h> EMSCRIPTEN_KEEPALIVE int add(int a, int b) { return a + b; } // Compile to WebAssembly // emcc example.c -o example.js -s EXPORTED_FUNCTIONS="['_add']" // JavaScript fetch('example.wasm').then(response => response.arrayBuffer() ).then(bytes => WebAssembly.instantiate(bytes, {}) ).then(results => { const add = results.instance.exports.add; console.log(add(2, 3)); // 5 }); ``` 🎛️ 用於多執行緒的 Web Worker --------------------- Web Workers 可讓您在背景執行緒中執行腳本,從而在 JavaScript 中啟用多執行緒。 ### 提示:將密集型任務分擔給 Web Worker 將繁重的計算移至 Web Worker 以保持主執行緒回應。 ``` // worker.js self.onmessage = (event) => { const result = performHeavyComputation(event.data); self.postMessage(result); }; function performHeavyComputation(data) { // Simulate heavy computation return data.split('').reverse().join(''); } // main.js const worker = new Worker('worker.js'); worker.postMessage('Hello, Web Worker!'); worker.onmessage = (event) => { console.log('Result from Worker:', event.data); }; ``` 🚀 優化 React 應用程式 --------------- React 很強大,但對於大型應用程式來說它可能會變得很慢。優化 React 效能對於無縫用戶體驗至關重要。 ### 提示:使用`React.memo`和`useMemo`進行記憶 使用`React.memo`來防止功能元件不必要的重新渲染。 ``` const ExpensiveComponent = React.memo(({ data }) => { // Expensive operations here return <div>{data}</div>; }); ``` 使用 useMemo 來記憶昂貴的計算。 ``` const MyComponent = ({ items }) => { const total = useMemo(() => { return items.reduce((sum, item) => sum + item.value, 0); }, [items]); return <div>Total: {total}</div>; }; ``` ### 提示:使用`React.lazy`和 Suspense 進行程式碼分割 拆分程式碼以僅在需要時載入元件。 ``` const LazyComponent = React.lazy(() => import('./LazyComponent')); const MyComponent = () => ( <React.Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </React.Suspense> ); ``` ⚙️ 使用高效率的資料結構 ------------- 選擇正確的資料結構會對效能產生重大影響。 ### 提示:使用映射進行快速鍵值查找 與物件相比,映射為頻繁加入和查找提供了更好的效能。 ``` const map = new Map(); map.set('key1', 'value1'); console.log(map.get('key1')); // value1 ``` ### 提示:使用集合進行快速唯一值存儲 集合提供了一種儲存唯一值的高效能方法。 ``` const set = new Set([1, 2, 3, 4, 4]); console.log(set.has(4)); // true console.log(set.size); // 4 ``` 結論 -- 進階 JavaScript 效能優化需要深入了解該語言及其生態系統。透過有效管理記憶體、利用 Service Workers、使用 WebAssembly 執行運算任務、將工作卸載給 Web Workers、優化 React 應用程式以及選擇高效的資料結構,您可以建立提供卓越使用者體驗的高效能 JavaScript 應用程式。 不斷探索和試驗這些技術,以釋放 JavaScript 的全部潛力。快樂編碼! 🚀 --- 原文出處:https://dev.to/parthchovatiya/advanced-javascript-performance-optimization-techniques-and-patterns-26g0

與我們一起參加由特邀評委 Ania Kubów 主持的 Wix Studio 挑戰賽:獎品為 3,000 美元!

--- 標題:與特別嘉賓評審 Ania Kubów 一起參加 Wix Studio 挑戰賽:獎品為 3,000 美元! 發表:真實 描述: 標籤: devchallenge, wixstudiochallenge, webdev, javascript 封面圖:https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8vfdvpqozr6h7ctfo6k.png 使用 100:42 的比例可獲得最佳效果。 ===================== 發表於: 2024-06-03 15:39 +0000 =========================== --- 我們非常高興地宣布我們與 Wix 的第一個合作挑戰。 [Wix Studio 挑戰賽](https://dev.to/challenges/wix)將持續到**7 月 7 日**,提供了使用網路提供的最受歡迎和最受歡迎的網站建立解決方案之一進行開發的機會。此挑戰有一個提示,並且有一種方法可以贏得整個 3,000 美元的獎金池。 🙀 發揮您的 JavaScript 技能,同時利用 Wix Studio 低程式碼環境來創造流暢的使用者體驗。您提交的內容將是您想要加入到您的產品組合中的真實產品開發的演示! 我們的提示 ----- 對於這項挑戰,您的任務是**使用 Wix Studio 建立創新的電子商務體驗。** Wix 提供了強大的視覺化建構器以及基於 JavaScript 的開發平台,使您能夠建立動態和互動式 Web 體驗。您可以完全控制您的網站,從前端設計到後端功能。 對於這項挑戰,我們只有一個要求:**您應該利用[Wix 的一組 API](https://www.wix.com/velo/reference)**和函式庫來增強使用者的購物體驗。功能越多,越快樂。 {% 卡 %} ### 小心 在您的應用程式中加入[服務外掛程式](https://dev.wix.com/docs/velo/articles/api-overview/service-plugins-spis)是進一步客製化您的購物體驗的有效方法。***然而**,這些將成為未來挑戰的中心*😉。因此,建議您主要圍繞您可以使用的**其他**API 進行建置來應對這一挑戰。 當然,我們希望看到您參加本次以及未來所有的 Wix 挑戰! {% 結束卡 %} 評審及獎項 ----- 我們將有史以來第一次邀請一位特邀嘉賓評審加入我們來應對這項挑戰! Ania Kubów[在 YouTube 上擁有超過 40 萬名訂閱者](https://www.youtube.com/aniakubow),是一位多產的軟體開發人員、教育家和課程建立者。阿尼亞已經教導了成千上萬的人如何在舒適的家中編碼。 {% 內嵌 https://dev.to/ania\_kubow %} 我們的獲勝者不僅將獲得我們迄今為止最大的現金獎勵,而且他們在離開時也會知道他們得到了 Ania 的認可。談論吹牛的權利! 提交的作品將根據以下內容進行評判: - 底層技術的使用 - 可用性和使用者體驗 - 無障礙 - 創造力 我們的提示的獲勝者將收到: - 3,000 美元 - 專屬開發者徽章 - 來自[DEV 商店](https://shop.forem.com)的禮物 **所有提交有效提交的參與者都**將在其 DEV 個人資料中收到完成徽章。 {% 卡 %} 如何參與 ---- 為了參與,您需要建立一個 Wix *Studio*網站(不僅僅是任何 Wix 網站!)並使用下面的提交範本發布貼文。所有提交的內容必須包含原始程式碼,並且不應包含自訂元素或 iFrame。 **建立 Wix Studio 網站的步驟** 1. 導航至[Wix Studio 頁面](https://www.wix.com/studio) 2. 點擊“開始建立” 3. 選擇“作為自由工作者” 4. 選擇“網頁開發” 5. 點擊“開始建立”! Wix 為 Wix Studio 提供免費套餐,您無需信用卡即可註冊。 請在提交之前查看我們的完整[規則、指南和常見問題解答頁面,](https://dev.to/challenges/wix)以便您了解我們的參與指南和官方競賽規則(例如資格要求)。 {% cta https://dev.to/new?prefill=---%0Atitle%3A%20%0Apublished%3A%20%0Atags%3A%20%20devchallenge%2C%20wixstudiochallenge%2C%20webdev%2C%20javascript %0A---%0A%0A*這%20是%20the%20%5BWix%20Studio%20Challenge%20%5D的%20a%20submission%20(https%3A%2F%2Fdev.to%2Fchallenges%2Fwix)。* %0A%0A%0A%23%23%20什麼%20I%20Built%0A%3C! --%20Share%20an%20概述%20about%20您的%20專案。 0A%23%23 %20Demo%0A%3C!--%20將%20a%20link%20分享到%20您的%20Wix%20Studio%20app%20和%20在此處包含%20some%20螢幕截圖%20。 80%99s%20JavaScript%20開發%20功能--%3E%0A%0A%3C!-- %20Which%20APIs%20and%20Libraries%20did%20you%20utilize%3F%20--%3E%0A%0A %3C!--%20Team%20Submissions%3A%20Please%20pick%20one%20member%20to%20publish% 20the%20submission%20and%20credit%20teammates%20by%20listing%2000and%20credit%20teammates%20by%20listing%200ir%200)% 20body%20of%20the%20post.%20--%3E%0A%0A%0A%3C! .%20--%3E%0A%0A%0A%3C!--%20感謝%20的%20參與!%20%E2%86%92%} Wix Studio 挑戰提交模板 {% 結束%} {% 結束卡 %} 社區和資源 ----- 我們鼓勵所有對挑戰有興趣的人加入[Wix 社群 Discord 上的開發人員](http://discord.gg/devs-on-wix)並進入他們的 #code-challenges 頻道。這將是尋求技術協助並與使用 Wix 建構的社群成員會面的地方。 由於我們的提示是關於建立電子商務體驗,因此我們希望向大家介紹他們的[電子商務 API 文件](https://dev.wix.com/docs/velo/api-reference/wix-ecom-backend/introduction)以及有關在 Wix 上[建立購物願望清單的教學課程](https://dev.wix.com/docs/develop-websites/articles/code-tutorials/wix-e-commerce-stores/adding-a-wishlist-to-a-wix-stores-site)。 😉 **其他資源** - [Wix 開發平台概述](https://dev.wix.com/docs/develop-websites/articles/getting-started/about-velo-by-wix) - [API文件](https://www.wix.com/velo/reference) - [Wix工作室論壇](https://forum.wixstudio.com/) 重要的日子 ----- - 6 月 26 日:Wix Studio 挑戰賽開始! - 7 月 7 日:提交截止時間為太平洋夏令時間晚上 11:59 - 7 月 9 日:得獎者公佈 我們希望您喜歡使用 Wix 靈活的開發工具進行建置,我們迫不及待地想看看您建置的內容!對挑戰有疑問嗎?請在下面詢問他們。 祝你好運,編碼愉快! --- 原文出處:https://dev.to/devteam/join-us-for-the-wix-studio-challenge-with-special-guest-judge-ania-kubow-3000-in-prizes-3ial

我正在尋找 FullStack 軟體開發人員職位

嘿,大家,希望你們一直做得很好並且感覺很好!我叫 Cherry Ramatis,目前正在尋找成為 FullStack 軟體開發人員的機會。 我熱衷於學習新事物並成為社區中的積極人物以實現知識民主化,因為我發現這是成為更好的專業人士並同時認識很酷的人(雙贏)的關鍵。我透過參加聚會、發表演講、為初級和中級開發人員提供指導、撰寫友好而足智多謀的文章以及總體上成為一個對任何人都平易近人且樂於助人的人物來做到這一點。 就我個人而言,我有三隻漂亮的狗,我喜歡在海灘上散步,也喜歡和朋友一起去卡拉 OK 酒吧(這是享受涼爽快樂時光的好機會👀) 稍微了解一下我 ------- - **名稱:**櫻桃拉馬蒂斯 - **目前居住地:**巴西聖保羅 - **我在專業領域中積極使用的技術:** - 打字稿/Javascript - 反應 - 下一個 - 角 - 承載者 - 碼頭工人 - Github 操作 - PostgreSQL - MongoDB - **我願意使用的技術:** - 紅寶石 - 紅寶石 on Rails - 靈丹妙藥 - 鳳凰 - **時間編碼總計:**約10年 - **專業時間編碼:**目前我已工作 6 年 - **線上和現場進行的演講數量:** - 在[He4rt 開發者](https://discord.gg/he4rt)社群進行了 3 場線上演講 - 在[ElixirDays](https://x.com/elaine_nw/status/1795459111678570643)發表 1 場面對面演講 - **發表文章數量:**目前發表文章21篇,瀏覽量約6.7萬,接觸人數達1.1萬 我引以為傲的成就 -------- - **參與巴西播客「Elixir em Foco」:** https://www.youtube.com/watch?v=zYl6ec4G4k8 - **被 dev.to 評為 2023 年排名前 7 位的作者之一:** https://dev.to/devteam/top-7s-top-authors-of-the-year-120m - **對大型資料庫公司的開源貢獻:** https://cloud-getting-started.scylladb.com/stable/build-with-ruby 我最喜歡的專案 ------- - **Regexer - 從單行語言到正規表示式的編譯器:** https://github.com/cherryramatisdev/regexer - **使用 Ruby 進行依賴注入的 HTTP 伺服器模組化架構:** https://github.com/cherryramatisdev/api-with-dry-ruby - **rust 和 elixir 中從偽語言到有效字節碼 BEAM 檔案的編譯器:** https://github.com/cherryramatisdev/beam\_studies - **使用 ruby 將異常轉換為結果單子的實驗:** https://github.com/cherryramatisdev/monadic-exceptions 你如何聯絡我 ------ - **領英:** https://www.linkedin.com/in/cherryramatis/ - **推特:** https://x.com/cherryramatis - **開發者:** https://dev.to/cherryramatis --- 原文出處:https://dev.to/cherryramatis/im-looking-for-a-fullstack-software-developer-role-417m

Javascript Proxy 的 7 個實際用例🧙

JavaScript 的`Proxy`物件是一個有用的工具,它開啟了一個充滿可能性的世界,讓您在應用程式中建立一些真正有用的行為。當與 TypeScript 結合使用時,Proxy 可以增強您以您可能認為不可能的方式管理和操作物件和函數的能力。在本文中,我們將透過實際範例探索代理的令人難以置信的實用性。 什麼是代理? ------ [Javascript 中的代理程式](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)是另一個物件(目標)的包裝器,它允許您攔截並重新定義該物件的基本操作,例如屬性查找、賦值、枚舉和函數呼叫。這意味著您可以在取得或設定屬性時新增自訂邏輯。這對於處理驗證、通知甚至自動資料綁定非常有用。 建立一個簡單的代理 --------- 讓我們開始看看如何建立代理。我們將從一個非常基本的範例開始,以防您以前從未見過代理。 ``` type MessageObject = { message: string; }; let target: MessageObject = { message: "Hello, world!" }; let handler: ProxyHandler<MessageObject> = { get: (obj, prop) => { return `Property ${String(prop)} is: ${obj[prop]}`; } }; let proxy: MessageObject = new Proxy(target, handler); console.log(proxy.message); // Output: Property message is: Hello, world! ``` 在此範例中,每當存取代理程式上的屬性時,都會呼叫處理程序的 get 方法,從而允許我們修改簡單存取屬性的行為。我相信您可以想像這帶來的所有不同的可能性。 現在讓我們來看看 7 個更有用的例子! ### 1. 自動填充屬性 代理程式可以在存取時動態填充物件屬性,這對於複雜物件的按需處理或初始化非常有用。 ``` type LazyProfile = { firstName: string; lastName: string; fullName?: string; }; let lazyProfileHandler = { get: (target: LazyProfile, property: keyof LazyProfile) => { if (property === "fullName" && !target[property]) { target[property] = `${target.firstName} ${target.lastName}`; } return target[property]; } }; let profile: LazyProfile = new Proxy({ firstName: "John", lastName: "Doe" }, lazyProfileHandler); console.log(profile.fullName); // Output: John Doe ``` ### 2. 運算計數 使用代理來計算對物件執行某些操作的次數。這對於除錯、監視或分析應用程式效能特別有用。 ``` type Counter = { [key: string]: any; _getCount: number; }; let countHandler = { get: (target: Counter, property: keyof Counter) => { if (property === "_getCount") { return target[property]; } target._getCount++; return target[property]; } }; let counter: Counter = new Proxy({ a: 1, b: 2, _getCount: 0 }, countHandler); counter.a; counter.b; console.log(counter._getCount); // Output: 2 ``` ### 3. 不可變物件 透過攔截並防止物件建立後對其進行任何更改,使用代理程式建立真正不可變的物件。 ``` function createImmutable<T extends object>(obj: T): T { return new Proxy(obj, { set: () => { throw new Error("This object is immutable"); } }); } const immutableObject = createImmutable({ name: "Jane", age: 25 }); // immutableObject.age = 26; // Throws error ``` ### 4. 方法鍊和流暢的接口 透過使用代理建立流暢的介面來增強方法鏈,其中每個方法呼叫都會傳回一個代理程式以啟用進一步的呼叫。 ``` type FluentPerson = { setName(name: string): FluentPerson; setAge(age: number): FluentPerson; save(): void; }; function FluentPerson(): FluentPerson { let person: any = {}; return new Proxy({}, { get: (target, property) => { if (property === "save") { return () => { console.log(person); }; } return (value: any) => { person[property] = value; return target; }; } }) as FluentPerson; } const person = FluentPerson(); person.setName("Alice").setAge(30).save(); // Output: { setName: 'Alice', setAge: 30 } ``` ### 5. 智慧緩存 這是我最喜歡的用例之一。實施智慧型快取機制,按需獲取或計算資料,然後儲存以供快速後續存取。 ``` function smartCache<T extends object>(obj: T, fetcher: (key: keyof T) => any): T { const cache: Partial<T> = {}; return new Proxy(obj, { get: (target, property: keyof T) => { if (!cache[property]) { cache[property] = fetcher(property); } return cache[property]; } }); } const userData = smartCache({ userId: 1 }, (prop) => { console.log(`Fetching data for ${String(prop)}`); return { name: "Bob" }; // Simulated fetch }); console.log(userData.userId); // Output: Fetching data for userId, then returns { name: "Bob" } ``` ### 6. 動態屬性驗證 代理可以動態地強制執行屬性分配規則。以下是如何確保在更改屬性之前滿足某些條件: ``` let user = { age: 25 }; let validator = { set: (obj, prop, value) => { if (prop === 'age' && (typeof value !== 'number' || value < 18)) { throw new Error("User must be at least 18 years old."); } obj[prop] = value; return true; // Indicate success } }; let userProxy = new Proxy(user, validator); userProxy.age = 30; // Works fine console.log(userProxy.age); // Output: 30 // userProxy.age = 'thirty'; // Throws error // userProxy.age = 17; // Throws error ``` ### 7. 觀察變化 代理程式的常見用例是建立可監視物件,以便在發生變更時通知您。 ``` function onChange(obj, onChange) { const handler = { set: (target, property, value, receiver) => { onChange(`Property ${String(property)} changed to ${value}`); return Reflect.set(target, property, value, receiver); } }; return new Proxy(obj, handler); } const person = { name: "John", age: 30 }; const watchedPerson = onChange(person, console.log); watchedPerson.age = 31; // Console: Property age changed to 31 ``` 使用代理的缺點 ------- 雖然代理非常有用,但它們有一些注意事項: 1. **效能**:代理程式會帶來效能開銷,尤其是在高頻操作中,因為代理程式上的每個操作都必須經過處理程序。 2. **複雜性**:能力越大,複雜度越高。代理的不正確使用可能會導致難以除錯的問題和可維護性問題。 3. **相容性**:代理程式無法為不支援 ES6 功能的舊版瀏覽器進行多填充,這限制了它們在需要廣泛相容性的環境中的使用。 結束 -- JavaScript 中的代理,尤其是與 TypeScript 一起使用時,提供了一種與物件互動的靈活方式。它們支援驗證、觀察和綁定等功能。無論您是建立複雜的使用者介面、開發遊戲還是處理伺服器端邏輯,理解和利用代理程式都可以為您提供更深層的控制和程式碼的複雜性。感謝您的閱讀,希望您學到新東西! 🎓 還有無恥的插頭🔌。如果您在敏捷開發團隊中工作並使用線上會議工具(例如規劃撲克或回顧),請查看我的免費工具[Kollabe](https://kollabe.com/) ! --- 原文出處:https://dev.to/mattlewandowski93/7-use-cases-for-javascript-proxies-3b29

Angular 18 的新增功能

介紹 -- 2024 年 5 月 22 日星期三,Angular 核心團隊發布了 Angular 新版本:版本 18。 該版本不僅穩定了最新的API,還引入了許多旨在簡化框架的使用並改善開發人員體驗的新功能。 這些新功能是什麼?請仔細閱讀,找出答案。 新的控制流程語法現已穩定 ------------ 當最新版本的 Angular 發佈時,引入了一種管理視圖流的新方法。提醒一下,這個新的控制流程直接整合到 Angular 模板編譯器中,使以下結構指令成為可選: - 動圖 - ngFor - ngSwitch / ngSwitchCase ``` <!-- old way --> <div *ngIf="user">{{ user.name }}</div> <!-- new way --> @if(user) { <div>{{ user.name }}</div> } ``` 這個新的 API 現已穩定,我們建議使用這個新語法。 如果您想將應用程式遷移到這個新的控制流,可以使用原理圖。 ``` ng g @angular/core:control-flow ``` 此外,新的 @for 語法取代了 ngFor 指令,迫使我們使用 track 選項來優化清單的渲染,並避免在變更期間完全重新建立清單。 開發模式中新增了兩個新警告: - 如果追蹤鍵重複,則會發出警告。如果所選鍵值在您的集合中不唯一,則會引發此警告。 - 如果追蹤鍵是整個專案並且選擇此鍵會導致整個清單的破壞和重新建立,則會發出警告。如果認為該操作成本太高(但門檻較低),則會出現此警告。 Defer 語法現已穩定 ------------ @defer 語法也在最新版本的 Angular 中引入,讓您定義一個在滿足條件時延遲載入的區塊。當然,此區塊中使用的任何第三方指令、管道或庫也將被延遲載入。 這是它的使用範例 ``` @defer(when user.name === 'Angular') { <app-angular-details /> }@placeholder { <div>displayed until user.name is not equal to Angular</div> }@loading(after: 100ms; minimum 1s) { <app-loader /> }@error { <app-error /> } ``` 提醒一句, - 只要不滿足@defer區塊條件,就會顯示@Placeholder區塊 - 當瀏覽器下載@defer區塊的內容時,將顯示@loading區塊;在我們的例子中,如果下載時間超過 100 毫秒,就會顯示區塊加載,並且顯示的最短持續時間為 1 秒。 - 如果下載@defer區塊時發生錯誤,將顯示@error區塊 Zone js 會發生什麼 ------------- Angular 18 引進了一種觸發偵測變更的新方法。此前,毫不奇怪,檢測更改完全由 Zone Js 處理。現在,偵測變化由框架本身直接觸發。 為了實現這一點,框架中加入了一個新的變更檢測調度程序 ( *ChangeDetectionScheduler* ),並且該調度程序將在內部使用來引發變更檢測。這個新的調度程序不再基於 Zone Js,並且預設與 Angular 版本 18 一起使用。 這個新的調度程序將引發檢測更改,如果 - 觸發範本或主機偵聽器事件 - 附加或刪除視圖 - 非同步管道接收新值 - 呼叫 markForCheck 函數 - 訊號的值發生變化等。 小文化時刻:此偵測變更是由於內部呼叫*ApplicationRef.tick*函數所致。 正如我上面提到的,由於Angular 18 版本一直基於這個新的調度程序,因此當您遷移應用程式時,不會出現任何問題,因為Angular 可能會收到Zone Js 和/或這個新調度程序的檢測更改通知。 但是,要回到 Angular 18 之前的行為,您可以使用provideZoneChangeDetection 函數,並將*ignoreChangesOutsideZone* setter 選項設為true。 ``` bootstrapApplication(AppComponent, { providers: [ provideZoneChangeDetection({ ignoreChangesOutsideZone: true }) ] }); ``` 另外,如果您希望僅依賴新的排程器而不依賴 Zone Js,則可以使用*ProvideExperimentalZonelessChangeDetection*函數。 ``` bootstrapApplication(AppComponent, { providers: [ provideExperimentalZonelessChangeDetection() ] }); ``` 透過實現*provideExperimentalZonelessChangeDetection*函數,Angular不再依賴Zone Js,這使得 - 如果專案的其他依賴項均不依賴它,則刪除 Zone js 依賴項 - 從 angular.json 檔案中的 polifills 中刪除區域 js 棄用 HttpClientModule ------------------- 自從 Angular 14 版本和獨立元件的到來以來,模組在 Angular 中已成為可選的,現在是時候看到第一個模組已棄用:我將其命名為 HttpClientModule 此模組負責為整個應用程式註冊 HttpClient 單例,以及註冊攔截器。 該模組可以輕鬆地替換為*ProvideHttpClient*函數,並提供支援 XSRF 和 JSONP 的選項。 這個函數有一個用於測試的孿生姊妹: *provideHttpClientTesting* ``` bootstrapApplication(AppComponent, { providers: [ provideHttpClient() ] }); ``` 像往常一樣,Angular 團隊提供了原理圖來幫助您遷移應用程式。 當發出*ng update @Angular/core @Angular /cli*命令時,如果在應用程式中使用,將發出遷移 HttpClientModule 的請求 內容後備 ---- ng-content 是 Angular 中的一個重要功能,尤其是在設計通用元件時。 此標籤可讓您投影自己的內容。然而,這項功能有一個重大缺陷。您無法為其指定預設內容。 從版本 18 開始,情況就不再如此。您可以在其中包含內容如果開發者沒有提供任何內容,將顯示的標籤。 我們以按鈕元件為例 ``` <button> <ng-content select=".icon"> <i aria-hidden="true" class="material-icons">send</i> </ng-content> <ng-content></ng-content> </button> ``` 使用按鈕元件時,如果沒有提供圖示類別的元素,則會顯示圖示傳送 表單事件:一種對表單事件進行分組的方法 ------------------- 這是社群很久以前提出的請求:有一個 api 將表單中可能發生的事件組合在一起;當我說事件時,我指的是以下事件 - 原始的 - 感動 - 狀態改變 - 重置 - 提交 Angular 18 版本公開了 AbstractControl 類別中的一個新事件屬性(允許 FormControl、FormGroup 和 FormArray 繼承該屬性),該屬性傳回一個 observable ``` @Component() export class AppComponent { login = new FormControl<string | null>(null); constructor() { this.login.events.subscribe(event => { if (event instanceof TouchedChangeEvent) { console.log(event.touched); } else if (event instanceof PristineChangeEvent) { console.log(event.pristine); } else if (event instanceof StatusChangeEvent) { console.log(event.status); } else if (event instanceof ValueChangeEvent) { console.log(event.value); } else if (event instanceof FormResetEvent) { console.log('Reset'); } else if (event instanceof FormSubmitEvent) { console.log('Submit'); } }) } } ``` 路由:重定向作為函數 ---------- 在最新版本的 Angular 之前,當您想要重新導向到另一個路徑時,可以使用*redirectTo*屬性。該屬性僅將一個字串作為其值 ``` const routes: Routes = [ { path: '', redirectTo: 'home', pathMath: 'full' }, { path: 'home', component: HomeComponent } ]; ``` 現在可以傳遞具有此屬性的函數。該函數將*ActivatedRouteSnapshot*作為參數,讓您可以從url中檢索queryParams或params。 另一個有趣的點是,這個函數是在註入上下文中呼叫的,使得注入服務成為可能。 ``` const routes: Routes = [ { path: '', redirectTo: (data: ActivatedRouteSnapshot) => { const queryParams = data.queryParams if(querParams.get('mode') === 'legacy') { const urlTree = router.parseUrl('/home-legacy'); urlTree.queryParams = queryParams; return urlTree; } return '/home'; }, pathMath: 'full' }, { path: 'home', component: HomeComponent }, { path: 'home-legacy', component: HomeLegacyComponent } ]; ``` 伺服器端渲染:兩個很棒的新功能 --------------- Angular 18 引進了兩個重要且期待已久的新伺服器端渲染功能 - 事件回放 - 國際化 ### 重播事件 當我們建立伺服器端渲染應用程式時,該應用程式會以 html 格式傳送回瀏覽器,顯示一個靜態頁面,然後由於水化現象而變得動態。在此水合階段期間,無法傳送對互動的回應,因此使用者互動會遺失,直到水合完成為止。 Angular 能夠記錄此水合作用階段的用戶交互,並在應用程式完全加載並交互後重播它們。 若要解鎖此功能,仍處於開發者預覽版,您可以使用 ServerSideFeature *withReplayEvents*函數。 ``` providers: [ provideClientHydration(withReplayEvents()) ] ``` ### 國際化 隨著 Angular 16 的發布,Angular 改變了頁面水合的方式。破壞性水合作用已被漸進性水合作用所取代。然而,當時缺乏一個重要的功能:國際化支持。 Angular 跳過了標記為 i18n 的元素。 有了這個新版本,這種情況就不再是這樣了。請注意,此功能仍處於開發預覽階段,可以使用*withI18nSupport*函數啟動。 ``` providers: [ provideClientHydration(withI18nSupport()) ] ``` 國際化 --- Angular 建議使用 INTL 原生 javascript API 來處理與 Angular 應用程式國際化相關的所有事務。 根據此建議, **@angular/common**套件公開的函數助手已被棄用。因此,不再建議使用 getLocaleDateFormat 等函數。 新的建構器包和棄用 --------- 到目前為止,自從 Angular 中出現 vite 以來,用於建立 Angular 應用程式的建構器位於以下套件中: **@angular-devkit/build-angular** 該套件包含 Vite、Webpack 和 Esbuild。對於將來僅使用 Vite 和 Esbuild 的應用程式來說,這個套件太重了。 考慮到這一潛在的未來,一個僅包含 Vite 和 Esbuild 的新包被建立,名稱為**@angular/build** 遷移到 Angular 18 時,如果應用程式不依賴 webpack(例如,沒有基於 Karma 的單元測試),則可以執行可選原理圖。此原理圖將修改 angular.json 檔案以使用新套件,並透過新增套件和刪除舊套件來更新 package.json。 重要的是,舊包可以繼續使用,因為它為新包提供了別名。 透過在專案的 node\_modules 中加入必要的依賴項,Angular 開箱即用地支援 Less Sass Css 和 PostCss。 然而,隨著新的**@angular/build**套件的到來,Less 和 PostCss 成為可選的,並且必須在 package.json 中明確作為開發依賴項。 當您遷移到 Angular 18 時,如果您希望使用新包,這些依賴項將自動新增。 不再需要降級非同步/等待 ------------ Zone js 不支援 Javascript 功能*async/await* 。 為了不限制開發人員使用此功能,Angular 的 CLI 將使用*async/await 的*程式碼轉換為「常規」Promise。 這種轉換稱為降級,就像它將 Es2017 程式碼轉換為 Es2015 程式碼一樣。 隨著應用程式不再基於 Zone Js,即使目前仍處於實驗階段,如果不再在 polyfill 中聲明 ZoneJs,Angular 將不再降級。 因此,應用程式的建置將更快、更輕。 新別名:by dev ---------- 從現在開始,當執行*ng dev*命令時,應用程式將以開發模式啟動。 實際上,ng dev 指令是*ngserve*指令的別名。 建立此別名是為了與 Vite 生態系統保持一致,特別是 npm run dev 指令。 未來 -- Angular 團隊再次交付了一個充滿新功能的版本,無疑將大大增強開發人員的體驗,並向我們展示 Angular 的未來一片光明。 未來我們可以期待什麼? 毫無疑問,性能和開發人員體驗持續改進。 我們還將看到基於訊號的表單、基於訊號的元件的引入,以及很快使用 @let 區塊聲明模板變數的能力。 --- 原文出處:https://dev.to/this-is-angular/whatnew-in-angular-18-60j

探索 JavaScript 中的解構

什麼是解構? ------ **解構**是 JavaScript 中一個非常酷的特殊語法功能,它允許我們從*陣列*、*物件*或其他可迭代結構中提取值並將它們指派給變數。 這是一種存取資料結構的屬性或元素的簡寫方式,而無需使用點表示法或陣列索引。 它對我們(用 JavaScript 寫程式的人)有什麼好處? ------------------------------ 解構有幾個好處,可以讓我們的程式碼更加簡潔、可讀和可維護! - ***提高可讀性***:解構透過減少複雜變數賦值和點符號的需要來簡化程式碼。 - ***更少的樣板程式碼***:您可以直接從資料結構中提取值,而無需建立中間變數。 - ***更簡潔的程式碼***:解構可以減少實現相同結果所需的程式碼行數。 - ***靈活性***:您可以解構任何類型的資料結構(物件、陣列、迭代),使其成為 JavaScript 工具包中的多功能工具。 有效的解構🚀使我們能夠編寫更具***表現力***、***可維護性***和***高效性的***程式碼,並且更容易理解和除錯。 基本範例 ---- ``` const person = { name: 'John', age: 30 }; const { name, age } = person; console.log(name); // "John" console.log(age); // 30 ``` 在這裡,我們解構了一個具有兩個屬性的物件`person` : `name`和`age` 。 解構 JavaScript 物件時,我們提取的值必須與物件中的鍵完全相同。您不能將`userName`取代該行中的`name` `const { name, age } = person;` 。這只是意味著 - `const { userName, age } = person;`行不通的。 但是,是的!我們可以在解構物件時套用別名。 EG- ``` const person = { name: 'John', age: 30 }; const { name:userName, age:userAge } = person; console.log(userName); // "John" console.log(userAge); // 30 ``` 您很可能在導入模組時第一次看到物件的解構。例如,當導入 exec 函數時 - ``` import { exec } from "node:child_process"; // ES Module syntax ``` ``` const { exec } = require("child_process"); // commonJS syntax ``` **同樣,我們也可以解構陣列**- ``` const numbers = [4, 5, 6]; const [x, y, z] = numbers; console.log(x); // 4 console.log(y); // 5 console.log(z); // 6 ``` 在這裡,當解構陣列時,您不需要使用別名將任何元素指派給自訂變數名稱。因為陣列元素只是值,所以它們不與某些鍵綁定。 預設值 --- 如果物件中不存在屬性,則解構允許您為變數指派預設值。 ``` const person = { name: 'John' }; const { name = 'Anonymous', age } = person; // age will be undefined console.log(name); // "John" console.log(age); // undefined ``` 這裡,字串值`'John'`沒有被變數`name`中的值`'Anonymous'`替換,因為它已經存在於物件中。 然而 - ``` const person = { name: 'John' }; const { name, age = 30 } = person; // age defaults to 30 if not present console.log(name); // "John" console.log(age); // 30 ``` 傳播文法 ---- **擴展**語法或**運算子**`(...)`可以與解構一起使用,以將陣列的剩餘元素或物件的屬性捕獲到新變數中。 - 使用陣列的擴充語法 - ``` const numbers = [1, 2, 3, 4, 5]; const [first, second, ...rest] = numbers; console.log(first); // 1 console.log(second); // 2 console.log(rest); // [3, 4, 5] (remaining elements) ``` - 物件的擴展語法 - ``` const person = { name: 'John', age: 30, city: 'New York' }; const { name, ...info } = person; console.log(name); // "John" console.log(info); // { age: 30, city: "New York"} (remaining properties) ``` 嵌套解構 ---- 解構可以嵌套以從深度嵌套的物件或陣列中提取值。 ``` const data = { user: { name: 'Alicia', origin: 'Romania', eyes: 'blue', address: { city: 'London', } } }; const { user: { name, address: { city } } } = data; console.log(name); // "Alicia" console.log(city); // "London" ``` 函數參數列表中的解構 ---------- 假設我們有一個名為`credentials`的JavaScript物件 - ``` const credentials = { name: 'Debajyati', age: 20, address: { city: 'Kolkata', state: 'West Bengal', country: 'India' }, phone: '', email: '', hobbies: ['reading', 'listening to music', 'coding', 'watching Anime'], skills: { programming: true, blogging: true, singing: false } } ``` 名為`showCredentials`的函數只接受 1 個參數值,該參數值是一個物件,而 Standard 會根據某些物件屬性輸出一個字串。 好吧,我們可以這樣寫函數定義 - ``` function showCredential(obj) { const hasSkill = (skill) => obj.skills[skill]; console.log( `${obj.name} is ${obj.age} years old.\n Lives in ${obj.address.city}, ${obj.address.country}.\n`, `He has the following hobbies: ${obj.hobbies.join(", ")}`, ); if (hasSkill("programming")) { console.log(`He is a programmer.`); } if (hasSkill("singing")) { console.log(`He is a singer.`); } if (hasSkill("blogging")) { console.log(`He is also a tech blogger.`); } } ``` 用 - 來呼叫它 ``` showCredential(credentials); ``` 得到這個輸出 - ``` Debajyati is 20 years old. Lives in Kolkata, India. He has the following hobbies: reading, listening to music, coding, watch ing Anime He is a programmer. He is also a tech blogger. ``` 相反,我們可以在定義函數時解構參數清單中的物件參數。像這樣 - ``` function showCredential({ name, age, address: { city, country}, hobbies, skills }) { const hasSkill = (skill) => skills[skill]; console.log( `${name} is ${age} years old.\n Lives in ${city}, ${country}.\n`, `He has the following hobbies: ${hobbies.join(", ")}`, ); if (hasSkill("programming")) { console.log(`He is a programmer.`); } if (hasSkill("singing")) { console.log(`He is a singer.`); } if (hasSkill("blogging")) { console.log(`He is also a tech blogger.`); } } ``` 給出相同的輸出。 &gt; | :資訊來源: 注意| |----------------------------------------| 函數仍然只接受一個參數。解構不會增加函數參數清單中的參數數量。 此外,呼叫該函數也沒有改變。依然是—— ``` showCredential(credentials); ``` ### 那麼,為什麼要解構函數參數列表中的物件呢? 雖然函數參數清單中的解構一開始可能看起來很麻煩或乏味,但它有非常重要的好處。 #### 需要考慮的要點 - ***更安全的程式碼:*** 解構可以清楚地表明函數需要哪些屬性,有助於防止錯誤。如果傳遞的物件中缺少屬性,解構將導致函數執行期間出現錯誤,有助於及早發現潛在問題。 - ***減少冗長:*** 透過直接將屬性提取到參數清單中的變數中,可以避免使用點表示法重複存取物件屬性。這導致函數定義更清晰、更簡潔。 - ***注重功能:*** 透過在參數清單中進行解構,您可以將資料存取邏輯與函數的核心功能分開。這改進了程式碼組織並使函數的目的更加清晰。 解構字串 ---- 就像我們如何解構陣列一樣,我們也可以將字串解包為陣列元素。巧妙地運用我們的智慧。 ``` const fruit = 'grape'; const [first, second, ...rest] = fruit; const animal = rest.join(''); console.log(animal); // ape ``` > | :警告:記住! |------------------------| 當您使用展開運算子`(...)`捕獲字串中的剩餘字元時,您不會得到字串。您將會得到這些字元的陣列。 解構的一些方便的應用範例 ------------ - ***沒有第三個變數的交換解構***: JavaScript 傳統上需要一個臨時變數來交換兩個變數的值。解構提供了一種更簡潔、更易讀的方式來實現這一目標。 ``` - Before Destructuring: ``` ``` let a = 10; let b = 20; let temp = a; a = b; b = temp; console.log(a, b); // Output: 20 10 ``` ``` - After Destructuring: ``` ``` let a = 10; let b = 20; [a, b] = [b, a]; console.log(a, b); // Output: 20 10 ``` ``` So nifty & elegant✨! Isn't it? ``` - ***解構函數傳回值***:函數可以以陣列或物件的形式傳回多個值。解構允許您將這些返回值解包到單獨的變數中,從而提高程式碼清晰度。 假設您有一個從 API 取得資料並傳回回應物件的函數: ``` function getUserUpdates(id) { // Simulating some API call with a GET request return { data: { player: response.group.names[id], brain: "rotting", powerLevel: Number(response.group.power[id]), useAsDecoy: true, }, statusCode: Number(response.status), }; } ``` 在建立 API 或處理伺服器回應的上下文中,它提供了增強程式碼品質和可維護性的獨特優勢。 存取各個屬性將變得輕而易舉,因為您可以在函數呼叫本身期間直接將所需的屬性從函數的返回值提取到單獨的變數中。 ``` const { data: {player, useAsDecoy, powerLevel}, statusCode, } = getUserUpdates(1); ``` 每當函數傳回物件並且您對特定屬性值感興趣時,請始終立即套用解構。 如果您仍然認為返回值的解構不是一個好主意,那麼這另外兩個優點可能會說服您 - (A)***簡化的心智模型:***解構簡化了將使用您的函數的開發人員理解資料流所需的思考過程。開發人員可以專注於解構模式中使用的變數名稱所傳達的含義,而不是記住複雜的屬性存取鏈。這減少了認知負擔並促進更好的程式碼理解。 (B)***簡化複雜回傳物件的樣板程式碼:*** 當函數傳回具有大量或嵌套屬性的物件時,解構會顯著減少單獨存取它們所需的樣板程式碼。這使得程式碼庫更加簡潔、更簡潔,從而提高了整體程式碼品質。 - ***帶條件的解構***:解構可以與條件語句結合起來,根據物件的結構來處理不同的場景。如果您有一個接收具有可選屬性的物件的函數: ``` function greetUser(user) { const { name = "Anonymous" } = user || {}; // Destructuring with default value console.log(`Hello, ${name}!`); } greetUser({ name: "Bob" }); // Output: "Hello, Bob!" greetUser({}); // Output: "Hello, Anonymous!" (no name property) greetUser(undefined); // Output: "Hello, Anonymous!" (function receives no argument) ``` 結論 -- 在整篇文章中,我們了解到**「解構」**是 JavaScript 中一個強大且多功能的功能,可以顯著提高程式碼的可讀性、可維護性和效率。透過有效地使用解構技術,您可以編寫更乾淨、更簡潔且不易出錯的程式碼。因此,擁抱解構並將您的 JavaScript 技能提升到一個新的水平! 如果您發現這篇文章有幫助,如果這個部落格為您的時間和精力增加了一些價值,請透過給這篇文章點讚來表達一些愛,並與您的朋友分享。 請隨時透過[Twitter](https://twitter.com/ddebajyati) 、 [LinkedIn](https://www.linkedin.com/in/debajyati-dey)或[GitHub](https://github.com/Debajyati)與我聯繫:) 快樂編碼🧑🏽‍💻👩🏽‍💻!祝你有個美好的一天! 🚀 --- 原文出處:https://dev.to/ddebajyati/exploring-destructuring-in-javascript-5a24

您可以在開源中貢獻這 25 個專案

受資助計畫的聲譽非常好,因為它們獲得了大量資金並得到了風險投資的支持。 有很多開源專案,你絕對應該為這些專案做出貢獻,特別是因為它們的可信度要高得多。 也許你有機會獲得直接的工作機會,畢竟你真的不知道誰在開源中關注你! 我只保留了活躍的專案(最後一次提交不到 2 個月),所以它會很有用。讓我們保持簡短和直接。 --- 1. [Taipy](https://github.com/Avaiga/taipy) - 資料和人工智慧演算法融入生產級網路應用程式。 -------------------------------------------------------------------- ![打字](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd10iiofzmt4or4db6ej.png) Taipy 是用於輕鬆、端到端應用程式開發的完美 Python 程式庫,具有假設分析、智慧型管道執行、內建調度和部署工具。 它用於為基於 Python 的資料和人工智慧應用程式建立 GUI 介面並改進資料流管理。 關鍵是性能,而 Taipy 是完美的選擇,尤其是與 Streamlit 相比。您可以閱讀 Marktechpost 發表的[Taipy 與 Streamlit](https://www.marktechpost.com/2024/03/15/taipy-vs-streamlit-navigating-the-best-path-to-build-python-data-ai-web-applications-with-multi-user-capability-large-data-support-and-ui-design-flexibility/)的詳細比較。 - 💰 獲得總資金 500 萬美元。 - 🚀 使用的主要語言是Python。 Taipy 在 GitHub 上有近 10k 顆星,並且正在發布`v3.1`版本。 https://github.com/Avaiga/taipy Star Taipy ⭐️ --- 2. [Hoppscotch](https://github.com/hoppscotch/hoppscotch) - API 開發生態系統。 ----------------------------------------------------------------------- ![跳房子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75cjol6454uvrnth524y.png) Hoppscotch 是一個輕量級、基於 Web 的 API 開發套件。它是從頭開始建置的,考慮到了易用性和可存取性。 Hoppscotch 與 Postman 非常相似,但提供了一些不同的功能。這就是儀表板的樣子,您可以在[hoppscotch.io](https://hoppscotch.io/)上進行即時測試。 ![跳房子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2f6ck92qdpd99in6wav.png) 即使測試本機 API,Postman 也要求您保持線上狀態。使用 Hoppscotch,您可以在沒有網路連線的情況下使用 API。 甚至 Web 應用程式也可以透過本機快取離線執行並充當 PWA,讓您可以隨時隨地測試 API! Hoppscotch 也提供私人工作空間。請參閱[完整功能清單](https://github.com/hoppscotch/hoppscotch?tab=readme-ov-file#features)。 ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d36kmr72z11h71nnvhf5.png) 最好的部分也是必要的部分是他們提供完整的[文件](https://docs.hoppscotch.io/),其中包括指南、文章、支援和變更日誌,以便您可以在這裡看到所有內容。 ![2023年已結束](https://hoppscotch.com/images/blog-hoppscotch-wrapped-2023.png) - 💰 獲得總資金 300 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Hoppscotch 在 GitHub 上擁有超過 60k 顆星,有 300 多個活躍問題和 200 多個貢獻者。 https://github.com/hoppscotch/hoppscotch 明星跳房子 ⭐️ --- 3. [Daily](https://github.com/dailydotdev/daily) - 每個開發者都值得擁有的首頁。 ----------------------------------------------------------------- ![日常的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvzd1auk8wet7vv5ev37.png) 這是一個專業網絡,您可以在其中閱讀與開發者生態系統相關的文章和個人化動態訊息。 他們匯總了來自許多組織(例如 Hacker News、Dev、Hashnode 等)的各種主題的有價值的帖子。您可以投票、加書籤,甚至建立自己的小隊。 ![小隊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqqkl42pja53ssywltyl.png) 我是其中一些功能的粉絲,如果我解釋所有內容,我會花費幾個小時,所以最好檢查一下。 這是我個人最喜歡的開源專案之一。你可以查看我的[每日個人資料](https://app.daily.dev/anmolbaranwal)。 - 💰 獲得總資金 1100 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Dailydotdev 在 GitHub 上擁有 17k+ 顆星。 https://github.com/dailydotdev/daily 明星日報 ⭐️ --- 4. [Requestly](https://github.com/requestly/requestly) - 瀏覽器的 HTTP 攔截器。 ----------------------------------------------------------------------- ![請求地](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jnfzpqe827qxm11a1tm.png) Requestly 的建置是為了透過攔截和修改 HTTP 請求來節省開發人員的時間。 Requestly 為前端開發人員提供必要的工具和整合協助,幫助他們以 10 倍的速度編寫、測試和偵錯程式碼。 Requestly 減少了對後端開發人員和開發和測試需求環境的依賴。 使用 Requestly,開發人員可以建立模擬、測試、驗證和覆蓋 API 回應,修改請求和回應標頭,設定重定向(映射本機、映射遠端),並使用 Requestly 會話進行更快的偵錯。 您可以看到[完整功能](https://github.com/requestly/requestly?tab=readme-ov-file#-features)的清單。 - 💰 獲得 50 萬美元的種子資金。 - 🚀 使用的主要語言是 TypeScript。 Requestly 在 GitHub 上擁有超過 1,800 顆星,並且正在快速成長。 https://github.com/requestly/requestly 為請求加星號 ⭐️ --- 5.[重新發送](https://github.com/resend)- 給開發人員的電子郵件。 ------------------------------------------------ ![重發](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a7diqqs4n4yrshxf22l3.png) 電子郵件可能是人們溝通的最重要的媒介。然而,我們需要停止像 2010 年那樣開發電子郵件,並重新思考 2022 年及以後如何開發電子郵件。它應該針對我們今天建立網頁應用程式的方式進行現代化。 他們提供了許多與我們正在使用的技術堆疊相對應的不同儲存庫。請隨意探索其中每一個。 ![重新發送集成](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jmx7q5i4wrsnwgcuvwk.png) - 💰 獲得 350 萬美元種子資金。 - 🚀 使用的主要語言是 TypeScript(React 電子郵件)。 Resend(React email)在 GitHub 上擁有超過 12,500 顆星,並被超過 7,500 名開發者使用。 https://github.com/resend 星標重新發送 ⭐️ --- 6. [Buildship](https://github.com/rowyio/buildship/) - 由人工智慧驅動的低程式碼視覺後端建構器。 --------------------------------------------------------------------------- ![建造船](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzlrynz5xephv4t9layd.png) 對於您正在使用無程式碼應用程式建構器(FlutterFlow、Webflow、Framer、Adalo、Bubble、BravoStudio...)或前端框架(Next.js、React、Vue...)建立的應用程式,您需要一個後端來支援可擴展的 API、安全工作流程、自動化等。 BuildShip 為您提供了一種完全視覺化的方式,可以在易於使用的完全託管體驗中可擴展地建立這些後端任務。 這意味著您無需在雲端平台上爭論或部署事物或執行 DevOps。只需立即建造和發貨 🚀 他們甚至與 TypeSense 合作並且發展得非常快! ![建造船](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6oc3rc713mjg9cwqj7d4.png) 我嘗試過Buildship,它很強大。 - 💰 私人資金(由 Google、Vercel、Figma 等支持)。 - 🚀 使用的主要語言是 TypeScript。 它在 GitHub 上有 260 多顆星,使用 Rowy 完成,有 5800 顆星。 https://github.com/rowyio/buildship/ 明星 BuildShip ⭐️ --- 7. [Cal](https://github.com/calcom/cal.com) - 為所有人安排基礎設施。 --------------------------------------------------------- ![卡爾](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ccagnexb805xzpewfy5.png) 這是有史以來最活躍的專案之一。我也透過 Cal 的 Algora 看過很多付費演出。 早些時候,我使用 Calendly,但我將其切換到 Cal,特別是因為它們在您可以建立的連結方面提供了更大的靈活性。 例如,我有一個協作連結,人們可以在其中選擇會議的持續時間並修復其他連結中的時間安排。您可以將其附加到幾乎所有應用程式,例如 GMeet、Zoom,如果您想參加付費會議,甚至可以同步付款。應用程式整合的[總選項](https://cal.com/apps)幾乎令人難以置信:) ![整合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/anesuu0ux6ejz886irnt.png) 您可以做很多事情,包括自動化工作流程,所以只需檢查一下即可。 ![工作流程儀表板](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kc0x5vq54joov98wwq9h.png) - 💰 獲得總資金(A 輪)3240 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Cal 在 GitHub 上擁有超過 29,000 顆星,並擁有超過 600 名貢獻者。 https://github.com/calcom/cal.com Star Cal ⭐️ --- 8. [Penpot](https://github.com/penpot/penpot) - 完美協作的設計工具。 ---------------------------------------------------------- ![筆筒](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mooryn8zodod2mkpzefn.png) Penpot 是第一個用於設計和程式碼協作的開源設計工具。設計師可以大規模建立令人驚嘆的設計、互動式原型和設計系統,而開發人員則可以享受現成的程式碼,並使他們的工作流程變得簡單、快速。所有這一切都沒有任何切換戲劇性的情況。 完全免費並符合開放標準(SVG、CSS 和 HTML)。 一次性查看[庫、模板](https://penpot.app/libraries-templates)和[功能](https://penpot.app/features)的清單。 觀看以下影片體驗`Penpot 2.0` 。 - 💰 獲得總資金 800 萬美元。 - 🚀 使用的主要語言是 Clojure。 Penpot 在 GitHub 上擁有超過 28,500 顆星,目前已發布`v2.0`版本。 https://github.com/penpot/penpot 星星筆罐 ⭐️ --- 9. [Appsmith](https://github.com/appsmithorg/appsmith) - 建立管理面板、內部工具和儀表板的平台。 ---------------------------------------------------------------------------- ![應用史密斯](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rt7s0r3wz2leec83cl17.png) 管理面板和儀表板是任何軟體創意(在大多數情況下)的一些常見部分,我嘗試從頭開始建立它,這會帶來很多痛苦和不必要的辛苦工作。 您可能已經看到組織建立了內部應用程式,例如儀表板、資料庫 GUI、管理面板、批准應用程式、客戶支援儀表板等,以幫助其團隊執行日常操作。正如我所說,Appsmith 是一個開源工具,可以實現這些內部應用程式的快速開發。 首先,請觀看這個 YouTube 影片,該影片在 100 秒內解釋了 Appsmith。 嵌入 https://www.youtube.com/watch?v=NnaJdA1A11s 他們提供拖放小部件來建立 UI。 您可以使用 45 多個可自訂的小工具在幾分鐘內建立漂亮的響應式 UI,而無需編寫一行 HTML/CSS。尋找[小部件的完整清單](https://www.appsmith.com/widgets)。 ![按鈕點擊小工具](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqpnnslvsvjl4gifseon.png) ![驗證](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/489fly7tvknz2uv2mgei.png) 您可以閱讀[文件](https://docs.appsmith.com/)並使用這[20 多個範本](https://www.appsmith.com/templates)中的任何一個,以便您可以快速入門。 - 💰 獲得 500 萬美元種子資金。 - 🚀 使用的主要語言是 TypeScript。 Appsmith 在 GitHub 上擁有超過 32k 顆星,發布了 200 多個版本。 https://github.com/appsmithorg/appsmith Star Appsmith ⭐️ --- 10.[二十](https://github.com/twentyhq/twenty)- Salesforce 的現代替代品。 --------------------------------------------------------------- ![二十](https://framerusercontent.com/images/oclg8rdRgBnzeLnSJOfettLFjI.webp) 我們花了數千個小時來研究Pipedrive 和Salesforce 等傳統CRM,以使它們與我們的業務需求保持一致,但最終卻感到沮喪——定制非常複雜,而且這些平台的封閉生態系統可能會讓人感到受到限制。 Twenty 是一個現代化、功能強大、價格實惠的平台,用於管理您的客戶關係。您可以閱讀[使用者指南](https://twenty.com/user-guide)。 ![二十](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tucrt5pk9piyswnt9q77.png) - 💰 獲得 75.9 萬美元的種子資金。 - 🚀 使用的主要語言是 TypeScript。 Twenty 在 GitHub 上擁有超過 14,500 顆星,擁有 200 多名貢獻者。 https://github.com/twentyhq/twenty 二十星 ⭐️ --- 11.[繼續](https://github.com/continuedev/continue)-AI程式碼助手。 -------------------------------------------------------- ![繼續 gif](https://github.com/continuedev/continue/raw/main/docs/static/img/understand.gif) Continue 是領先的開源 AI 程式碼助理。您可以連接任何模型和任何上下文,以在[VS Code](https://marketplace.visualstudio.com/items?itemName=Continue.continue)和[JetBrains](https://plugins.jetbrains.com/plugin/22707-continue-extension)內建立自訂自動完成和聊天體驗。 > 選項卡可自動完成程式碼建議。 ![自動完成 gif](https://github.com/continuedev/continue/raw/main/docs/static/img/autocomplete.gif) > 重構您正在編碼的函數。 ![重構影像](https://github.com/continuedev/continue/raw/main/docs/static/img/inline.gif) > 詢問有關您的程式碼庫的問題。 ![程式碼庫](https://github.com/continuedev/continue/raw/main/docs/static/img/codebase.gif) > 快速使用文件作為上下文 ![文件上下文 gif](https://github.com/continuedev/continue/raw/main/docs/static/img/docs.gif) 閱讀[快速入門指南](https://docs.continue.dev/quickstart)。 - 💰 獲得 210 萬美元種子資金。 - 🚀 使用的主要語言是 TypeScript。 Continue 在 GitHub 上有 12k+ 顆星,並且發布了`v0.8`版本。 https://github.com/continuedev/continue 星繼續 ⭐️ --- [12.Refine](https://github.com/refinedev/refine) - 面向企業的開源 Retool。 ------------------------------------------------------------------ ![精煉](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wsti2yfikrhc9nggov5.png) Refine 是一個元 React 框架,可以快速開發各種 Web 應用程式。 從內部工具到管理面板、B2B 應用程式和儀表板,它可作為建立任何類型的 CRUD 應用程式(例如 DevOps 儀表板、電子商務平台或 CRM 解決方案)的全面解決方案。 ![電子商務](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xry9381y4s36emgb9psr.png) 您可以在一分鐘內使用單一 CLI 命令進行設定。 它具有適用於 15 多個後端服務的連接器,包括 Hasura、Appwrite 等。 但最好的部分是,Refine `headless by design` ,從而提供無限的樣式和自訂選項。 你可以看到[模板](https://refine.dev/templates/)。 ![範本](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87vbx5tqyicb9gmgirka.png) - 💰 獲得總資金 380 萬美元。 - 🚀 使用的主要語言是 TypeScript。 它們在 GitHub 上擁有大約 25,000 顆星,並被超過 3,000 名開發人員使用。 https://github.com/refinedev/refine 星際精煉 ⭐️ --- 13. [Revideo](https://github.com/redotvideo/revideo) - 使用程式碼建立影片。 ----------------------------------------------------------------- ![審查](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ttwzahj6kfgllj0aknt1.png) Revideo 是一個用於程式化影片編輯的開源框架。它是從令人驚嘆的 Motion Canvas 編輯器分叉出來的,將其從獨立的應用程式轉變為開發人員可以用來建立整個影片編輯應用程式的庫。 Revideo 可讓您在 Typescript 中建立視訊範本並部署 API 端點以使用動態輸入呈現它們。它還提供了一個React播放器元件來即時預覽瀏覽器中的變化。 - 💰 獲得總資金 500 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Revideo 在 GitHub 上有 1.2k 顆星,活躍問題非常少。簡而言之,這是一個完美的、不那麼擁擠的貢獻專案。 https://github.com/redotvideo/revideo 明星重錄 ⭐️ --- 14.[百萬](https://github.com/aidenybai/million)- 讓你的 React 速度提高 70%。 ------------------------------------------------------------------ ![百萬](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afs9dm1eujmajxn0rng9.png) Million.js 是一個極其快速且輕量級的最佳化編譯器,可將元件速度提高 70%。自己探索吧! ![特徵](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vozcs5gd57rwlp3jjmr4.png) - 💰 獲得總計 50 萬美元的資金。 - 🚀 使用的主要語言是 TypeScript。 Million 在 GitHub 上擁有超過 15,500 顆星,並被超過 3000 名開發者使用。 https://github.com/aidenybai/million 明星百萬⭐️ --- 15. [FlowiseAI](https://github.com/FlowiseAI/Flowise) - 拖放 UI 來建立您的客製化 LLM 流程。 ------------------------------------------------------------------------------ ![弗洛伊薩伊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5bp43nil764fhe4a05z.png) Flowise 是一款開源 UI 視覺化工具,用於建立客製化的 LLM 編排流程和 AI 代理程式。 ![整合](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahk2ovjrpq1qk3r5pfot.png) 您可以閱讀[文件](https://docs.flowiseai.com/)。 ![流程化人工智慧](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/trkltpn5lk1y1pte0smd.png) - 💰 從 YCombinator 獲得資金(不知道多少)。 - 🚀 使用的主要語言是 TypeScript。 FlowiseAI 在 GitHub 上擁有超過 26,500 個 Star,並擁有超過 13,000 個分叉,因此具有良好的整體比率。 https://github.com/FlowiseAI/Flowise 明星 FlowiseAI ⭐️ --- 16.[觸發器](https://github.com/triggerdotdev/trigger.dev)——後台作業平台。 --------------------------------------------------------------- ![扳機](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iaoox3qwmc397x9ckmw4.png) Trigger.dev v3 可以輕鬆編寫可靠的長時間執行任務而不會逾時。 在它們所屬的地方建立作業:在您的程式碼庫中。像您已經習慣的那樣進行版本控制、本地主機、測試、審查和部署。 您可以選擇在自己的基礎架構上使用觸發器雲端或自架觸發器。 閱讀文件中的[快速入門指南](https://trigger.dev/docs/v3/quick-start)。 - 💰 獲得總資金 300 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Trigger 在 GitHub 上有 7,500 顆星,目前已發布`v3.1`版本。 https://github.com/triggerdotdev/trigger.dev 星觸發器 ⭐️ --- 17. [Tiptap](https://github.com/ueberdosis/tiptap) - 無頭富文本編輯器框架。 ---------------------------------------------------------------- ![尖擊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdtmi7do65ks6f2mpsjd.png) Tiptap 編輯器是一個無頭、與框架無關的富文本編輯器,可以透過擴充功能進行自訂和擴充。它的無頭性質意味著它沒有固定的使用者介面,提供完全的設計自由(要快速入門,請參閱下面連結的 UI 模板)。 Tiptap 是基於高度可靠的 ProseMirror 庫。 Tiptap Editor 得到協作開源後端 Hocuspocus 的補充。 Editor 和 Hocuspocus 構成了 Tiptap Suite 的基礎。 我建議閱讀包含[範例](https://tiptap.dev/docs/editor/examples/default)和詳細程式碼的[文件](https://tiptap.dev/docs/editor/introduction)。 - 💰 獲得總資金 260 萬美元。 - 🚀 使用的主要語言是 TypeScript。 ![尖擊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/20c83ios6ugr1q6blqfq.png) Tiptap 在 GitHub 上擁有超過 24k 顆星,擁有 300 多名貢獻者。 https://github.com/ueberdosis/tiptap 明星 Tiptap ⭐️ --- 18. [Infisical](https://github.com/Infisical/infisical) - 秘密管理平台。 ----------------------------------------------------------------- ![內部的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrolzjdnkky1r694h9av.png) Infisical 是一個開源秘密管理平台,團隊可以用它來集中 API 金鑰、資料庫憑證和設定等秘密。 他們讓每個人(而不僅僅是安全團隊)都可以更輕鬆地進行秘密管理,這意味著從頭開始重新設計整個開發人員體驗。 ![內部](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3eu288l470du91b66pd.png) Infisical 還提供了一組工具來自動防止 git 歷史記錄的秘密洩露。可以使用預提交掛鉤或透過與 GitHub 等平台直接整合在 Infisical CLI 層級上設定此功能。 您可以閱讀[文件](https://infisical.com/docs/documentation/getting-started/introduction)並檢查如何[安裝 CLI](https://infisical.com/docs/cli/overview) ,這是使用它的最佳方式。 在使用整個原始程式碼之前一定要檢查他們的[許可證](https://github.com/Infisical/infisical/blob/main/LICENSE),因為他們有一些受 MIT Expat 保護的企業級程式碼,但不用擔心,大部分程式碼都是免費使用的。 - 💰 獲得總資金 290 萬美元。 - 🚀 使用的主要語言是 TypeScript。 他們在 GitHub 上擁有超過 12,500 顆星,發布了 130 多個版本。另外,Infiscial CLI 的安裝次數超過 540 萬次,因此非常值得信賴。 https://github.com/Infisical/infisical 明星 Infisical ⭐️ --- 19. [HyperDX](https://github.com/hyperdxio/hyperdx) - 統一會話重播、日誌、指標、追蹤和錯誤的可觀察平台。 ------------------------------------------------------------------------------- ![超DX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6r38lckflg0wmwlq6i4.png) HyperDX 透過將日誌、指標、追蹤、異常和會話重播集中並關聯到一處,幫助工程師快速找出生產中斷的原因。 Datadog 和 New Relic 的開源且開發人員友善的替代方案。閱讀[文件](https://www.hyperdx.io/docs)。 ![超DX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9g83r7408vr2oawc8s8p.png) - 💰 獲得總計 50 萬美元的資金。 - 🚀 使用的主要語言是 TypeScript。 HyperDX 在 GitHub 上擁有超過 6k 顆星。 https://github.com/hyperdxio/hyperdx 明星 HyperDX ⭐️ --- 20.[亮點](https://github.com/highlight/highlight)-全端監控平台。 ------------------------------------------------------- ![強調](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3p2ecjnrwbtskuqrkjv7.png) highlight.io 是為下一代開發人員(像您一樣!)提供的監控工具。與現有的古老、過時的工具不同,它們的目標是建立一個有凝聚力的、現代的、功能齊全的監控解決方案。 ![支援框架](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afaoao8954hobs7d2igw.png) - 💰 獲得總資金 850 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Highlight 在 GitHub 上有超過 7k 顆星。 https://github.com/highlight/highlight 星標亮點 ⭐️ --- 21. [Panora](https://github.com/panoratech/Panora) - 在幾分鐘內將整合目錄新增至您的 SaaS 產品。 ----------------------------------------------------------------------------- ![全景](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jzhhyl8t0xy2ueln8d4t.png) Panora 協助您將產品置於客戶日常工作流程的核心。 您的客戶希望他們的所有工具都能很好地協同工作。 Panora 避免您的團隊花費數百小時來建立和維護集成,而不是核心產品。 查看[快速入門指南](https://docs.panora.dev/quick-start)。 - 💰 獲得了 50 萬美元的總資金(可能更多)。 - 🚀 使用的主要語言是 TypeScript。 Panora 在 GitHub 上擁有 300 多個 star,並且處於非常早期的階段。 https://github.com/panoratech/Panora 明星 Panora ⭐️ --- 22. [Fleet](https://github.com/fleetdm/fleet) - IT、安全和基礎設施團隊的平台。 ---------------------------------------------------------------- ![艦隊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d47vi9uyn2hq3kx6s2h6.png) 針對擁有數千台電腦的 IT 和安全團隊的開源平台。專為 API、GitOps、webhooks、YAML 和人類而設計。 Fastly 和 Gusto 等組織使用 Fleet 進行漏洞報告、偵測工程、裝置管理 (MDM)、裝置運作狀況監控、基於狀態的存取控制、管理未使用的軟體授權等。 ![艦隊](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vfn75mjk5rfhb4bfjwp8.png) - 💰 獲得總資金 2500 萬美元。 - 🚀 使用的主要語言是 Go。 Fleet 在 GitHub 上擁有 2,500 顆星。 https://github.com/fleetdm/fleet 星際艦隊 ⭐️ --- 23. [Ballerine](https://github.com/ballerine-io/ballerine) - 用於風險決策的基礎設施和資料編排平台。 -------------------------------------------------------------------------------- ![舞者](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tnnrhyf6oj3dexdeyyuf.png) Ballerine 是一種開源風險管理基礎設施,可協助全球支付公司、市場和金融科技公司在整個客戶生命週期中自動為商家、賣家和使用者做出決策。 從開戶(KYC、KYB)、承銷和交易監控,使用靈活的規則和工作流程引擎、第 3 方插件系統、手動審核後台以及文件和資訊收集前端流程。 - 💰 獲得總資金 550 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Ballerine 在 GitHub 上擁有 2000 顆星,發布了 700 多個版本。 https://github.com/ballerine-io/ballerine 明星芭蕾舞者 ⭐️ --- 24. [Tooljet](https://github.com/ToolJet/ToolJet) - 用於建立業務應用程式的低程式碼平台。 ---------------------------------------------------------------------- ![工具噴射器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhipvjl2wnthjccgrpij.png) 我們都建立前端,但它通常非常複雜,並且涉及許多因素。這樣可以省去很多麻煩。 ToolJet 是一個開源低程式碼框架,可以用最少的工程工作來建置和部署內部工具。 ToolJet 的拖放式前端建構器可讓您在幾分鐘內建立複雜的響應式前端。 您可以整合各種資料來源,包括PostgreSQL、MongoDB、Elasticsearch等資料庫;具有 OpenAPI 規範和 OAuth2 支援的 API 端點; SaaS 工具,例如 Stripe、Slack、Google Sheets、Airtable 和 Notion;以及 S3、GCS 和 Minio 等物件儲存服務來取得和寫入資料。一切 :) 這就是 Tooljet 的工作原理。 ![工具噴射器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6vv09z7ioma1ce2ttei.png) 您可以在 ToolJet 中開發多步驟工作流程以自動化業務流程。除了建置和自動化工作流程之外,ToolJet 還可以在您的應用程式中輕鬆整合這些工作流程。 ![工作流程](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eh2vk3kih9fhck6okf67.png) 您可以閱讀[文件](https://docs.tooljet.com/docs/)並查看[操作指南](https://docs.tooljet.com/docs/how-to/use-url-params-on-load)。 - 💰 獲得總融資 620 萬美元(GitHub 是其中一名投資者)。 - 🚀 使用的主要語言是 JavaScript。 Tooljet 在 GitHub 上擁有超過 27,800 顆星和 500 多名貢獻者。 https://github.com/ToolJet/ToolJet Star Tooljet ⭐️ --- 25. [Mattermost-](https://github.com/mattermost/mattermost)整個軟體開發生命週期的安全協作。 --------------------------------------------------------------------------- ![最重要的](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/43p8f052h71ryhavrkms.png) Mattermost 是一個開源平台,用於在整個軟體開發生命週期中進行安全協作。 該儲存庫是 Mattermost 平台上核心開發的主要來源;它是用 Go 和 React 編寫的,並作為單一 Linux 二進位與 MySQL 或 PostgreSQL 一起執行。每個月 16 日都會在 MIT 許可下發布新的編譯版本。 - 💰 獲得總資金 7350 萬美元。 - 🚀 使用的主要語言是 TypeScript。 Mattermost 在 GitHub 上擁有超過 28,400 顆星,有 600 多個活躍問題和 900 多個貢獻者。 https://github.com/mattermost/mattermost Star Mattermost ⭐️ --- 我很驚訝這麼多受資助的專案使用 TypeScript 而不是 JavaScript。你是? 如果您知道任何其他資助專案或希望我製作第二部分。 請在評論中告訴我您最喜歡的清單。 祝你有美好的一天!直到下一次。 您可以加入我的開發者和技術作家社區,網址為[dub.sh/opensouls](https://dub.sh/opensouls) 。 關注 Taipy 以了解更多此類內容。 嵌入 https://dev.to/taipy --- 原文出處:https://dev.to/taipy/25-funded-projects-you-can-contribute-in-open-source-40lh

如何在行動裝置上測試本地網站

在建立網站時,開發人員通常需要測試他們的網站是否響應靈敏、經過優化並且在行動裝置上運作良好。如果他們不知道一種簡單且正確的方法來進行測試,那麼測試可能會令人沮喪。 在這篇文章中,我將向您展示如何透過三個簡單的步驟在行動裝置上測試本地網站。儘管瀏覽器開發工具可以提供幫助,但有時您可能需要更好的視覺化、清晰度和與專案的觸控互動。在這種情況下,在實際手機上進行測試可能比使用瀏覽器的行動螢幕更好。 要在手機上查看本地網站的即時預覽,請確保您的手機和桌面連接到相同 WiFi 網路。如果尚未安裝,請安裝[VS Code](https://code.visualstudio.com/)編輯器和[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)擴充功能。 在電話上測試本地網站的步驟 ------------- 下載 VS Code 編輯器及其 Liver Server 擴充功能後,現在請按照給定的 3 個步驟逐行查看手機上的本機專案: ### 1. 執行實時伺服器 首先,在 VS Code 中開啟專案資料夾。然後,點擊右下角的「上線」按鈕。這將為您的專案啟動本機開發伺服器,通常在連接埠`5500`上執行。 您的專案現在應該在預設的 Web 瀏覽器中執行。記下連接埠號碼(5500 或其他數字,如果不同)。 ![執行實時伺服器](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5bxampc1npsnupyvfwrf.jpg) ### 2. 尋找您的本地 IPv4 位址 接下來,您需要本機 IPv4 位址。開啟命令提示字元 (CMD),鍵入 ipconfig,然後按 Enter。在「無線 LAN 適配器 Wi-Fi」部分下尋找您的 IPv4 位址。它看起來像`192.168.1.68` 。 請記住,如果新設備連接或斷開與您的 WiFi 網路的連接,您的本地 IP 位址可能會發生變化。 ![尋找您的本機 IPv4 位址](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggaldbbpfdf26cbbqebk.jpg) ### 3. 在手機上查看您的專案 開啟手機上的瀏覽器並輸入您的 IPv4 位址,然後輸入連接埠號碼。 URL 應如下所示: `192.168.1.68:5500` 。 如果您的主 HTML 檔案未命名為 index.html,則需要在 URL 中包含檔案名,如下所示: `192.168.1.68:5500/filename.html` 。 ![在手機上查看您的專案](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qoy2k744fqngq9bsz35.jpg) 現在您應該在手機上看到專案的即時預覽。您在桌面上的 VS Code 中所做的任何更改都會立即反映在您的手機上,無需手動刷新。 常見錯誤故障排除 -------- 如果您遇到「無法存取網站」或類似內容的錯誤,請嘗試以下故障排除步驟: - **仔細檢查 IPv4 位址和連接埠號碼:**確保您在手機瀏覽器中輸入了正確的 IPv4 位址和連接埠號碼。 - **檢查網路連線:**確保您的手機和桌面連接到相同 WiFi 網路。 - **檢查檔案路徑:**如果您的主 HTML 檔案不是`index.html` ,請確保 URL 中包含正確的檔案路徑。 - **防火牆設定:**您電腦的防火牆可能阻止連線。調整設定以允許 Live Server 使用的連接埠號碼上的流量。 結論 -- 在這篇文章中,您學習如何在手機上查看專案的即時預覽。此方法適用於使用[HTML、CSS](https://www.codingnepalweb.com/category/html-and-css/)和[JavaScript](https://www.codingnepalweb.com/category/javascript/)以及其他框架專案建立的靜態專案。 如果您想提高編碼的準確性、速度和效能,請查看我的部落格文章《[面向 Web 開發人員的十大有用 VS 程式碼擴充》](https://www.codingnepalweb.com/top-vs-code-extensions-for-web-developers/) 。 如果您發現本指南有幫助,請與其他人分享! --- 原文出處:https://dev.to/codingnepal/how-to-test-local-website-on-mobile-devices-2p69

掌握整潔程式碼:開發人員的基本實踐

乾淨的程式碼是每個成功的軟體專案的基石。作為開發人員,編寫乾淨、可維護的程式碼的能力對於應用程式的效率和壽命至關重要。在本文中,我們將深入研究 JavaScript 中好的和壞的編碼實踐的十個範例,強調編寫乾淨程式碼並提供可操作的見解以幫助您提高開發技能的重要性。 例子 -- - 描述性變數名稱: ``` // Good: const totalPrice = calculateTotalPrice(quantity, unitPrice); ``` ``` // Bad: const t = calcPrice(q, uP); ``` 在一個很好的例子中,變數名稱具有描述性並清楚地表達了它們的目的,從而增強了程式碼的可讀性。相反,糟糕的範例使用神秘的縮寫,使其他人難以理解程式碼的意圖。 - 一致的格式: ``` // Good: function greet(name) { return `Hello, ${name}!`; } ``` ``` // Bad: function greet(name){ return `Hello, ${name}!` } ``` 一致的格式提高了程式碼的可讀性和可維護性。在一個很好的例子中,採用了適當的縮排和間距,並增強了程式碼結構。相反,壞例子缺乏一致性,使得程式碼更難遵循。 - 避免魔法數字: ``` // Good: const TAX_RATE = 0.1; const totalPrice = subtotal + (subtotal * TAX_RATE); ``` ``` // Bad: const totalPrice = subtotal + (subtotal * 0.1); ``` 幻數掩蓋了值的含義,並使程式碼更難維護。在很好的例子中,常數用於表示幻數,提高了程式碼的清晰度和可維護性。 - 單一責任原則: ``` // Good: function calculateTotalPrice(quantity, unitPrice) { return quantity * unitPrice; } function formatPrice(price) { return `$${price.toFixed(2)}`; } ``` ``` // Bad: function calculateAndFormatTotalPrice(quantity, unitPrice) { const totalPrice = quantity * unitPrice; return `$${totalPrice.toFixed(2)}`; } ``` 函數應該有單一的責任來提高程式碼的可重複使用性和可維護性。在這個很好的例子中,每個函數都執行特定的任務,並遵循單一職責原則。相反,壞例子將多個職責組合到一個函數中,違反了這個原則。 - 錯誤處理: ``` // Good: function fetchData(url) { return fetch(url) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .catch(error => { console.error('Error fetching data:', error); throw error; }); } ``` ``` // Bad: function fetchData(url) { return fetch(url) .then(response => response.json()) .catch(error => console.error(error)); } ``` 正確的錯誤處理可以提高程式碼的穩健性,並有助於更有效地辨識和解決問題。在好的範例中,錯誤得到了妥善處理,為開發人員提供了有意義的回饋。相反,壞範例缺乏全面的錯誤處理,可能導致靜默故障。 - 評論和文件: ``` // Good: // Calculate the total price based on quantity and unit price function calculateTotalPrice(quantity, unitPrice) { return quantity * unitPrice; } ``` ``` // Bad: function calculateTotalPrice(quantity, unitPrice) { // calculate total price return quantity * unitPrice; } ``` 註釋和文件增強了程式碼的可理解性並促進了開發人員之間的協作。在一個很好的範例中,清晰的註解描述了函數的用途,有助於程式碼理解。相反,壞例子提供的模糊評論幾乎沒有什麼價值。 - 適當的模組化: ``` // Good: export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } ``` ``` // Bad: function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } ``` 模組化程式碼透過將功能組織成內聚的單元來提高可重複使用性和可維護性。在好的例子中,函數被正確地封裝和匯出,促進程式碼重用。相反,壞例子缺乏模組化,使其更難以管理和擴展。 - DRY 原則(不要重複): ``` // Good: const greeting = 'Hello'; function greet(name) { return `${greeting}, ${name}!`; } ``` ``` // Bad: function greet(name) { const greeting = 'Hello'; return `${greeting}, ${name}!`; } ``` 重複的程式碼會增加錯誤的風險並使維護變得困難。一個很好的例子是,將重複的字串提取為常數,遵循DRY原則並提高程式碼的可維護性。相反,壞範例在函數內冗餘地定義了問候語。 - 有意義的函數名稱: ``` // Good: function calculateArea(radius) { return Math.PI * radius ** 2; } ``` ``` // Bad: function calc(r) { return Math.PI * r ** 2; } ``` 函數名稱應準確反映其用途,以增強程式碼可讀性。在這個很好的例子中,函數名稱“calculateArea”清楚地表明了它的功能。相反,糟糕的例子使用了神秘的縮寫(“calc”),讓人不清楚函數的作用。 - 可測試性: ``` // Good: function sum(a, b) { return a + b; } module.exports = sum; ``` ``` // Bad: function sum(a, b) { console.log(a + b); } ``` 編寫可測試的程式碼有利於自動化測試,確保程式碼的可靠性和穩定性。在很好的範例中,函數被匯出用於測試目的,從而可以輕鬆設定和執行測試。相反,壞範例包含副作用(console.log),使得測試函數的行為變得具有挑戰性。 - 正確使用資料結構: ``` // Good: const studentGrades = [90, 85, 95, 88]; const averageGrade = studentGrades.reduce((total, grade) => total + grade, 0) / studentGrades.length; ``` ``` // Bad: const grade1 = 90; const grade2 = 85; const grade3 = 95; const grade4 = 88; const averageGrade = (grade1 + grade2 + grade3 + grade4) / 4; ``` 使用適當的資料結構可以增強程式碼的可讀性和可維護性。在很好的例子中,陣列用於儲存學生成績,以便於操作和計算。相反,壞範例依賴單一變數,導致重複且容易出錯的程式碼。 - 處理非同步操作: ``` // Good: async function fetchData(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error('Network response was not ok'); } return await response.json(); } catch (error) { console.error('Error fetching data:', error); throw error; } } ``` ``` // Bad: function fetchData(url) { return fetch(url) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .catch(error => { console.error('Error fetching data:', error); throw error; }); } ``` 正確處理非同步操作可確保程式碼的可靠性和健全性。在一個很好的例子中,async/await 語法用於簡化非同步程式碼並優雅地處理錯誤。相反,壞範例使用嵌套的 Promise,導致回調地獄並降低程式碼可讀性。 - 依賴管理: ``` // Good: import { format } from 'date-fns'; ``` ``` // Bad: const dateFns = require('date-fns'); ``` 有效的依賴管理可以促進程式碼模組化和可擴展性。在一個很好的範例中,ES6 導入語法用於僅從“date-fns”庫導入所需的功能,從而減少不必要的導入並提高效能。相反,糟糕的範例使用 CommonJS require 語法,該語法導入整個“date-fns”模組,可能會使應用程式套件膨脹。 - 效能優化: ``` // Good: const sortedNumbers = [5, 2, 8, 1, 9]; sortedNumbers.sort((a, b) => a - b); ``` ``` // Bad: const unsortedNumbers = [5, 2, 8, 1, 9]; const sortedNumbers = unsortedNumbers.sort(); ``` 優化程式碼效能可確保高效執行並增強使用者體驗。在一個很好的範例中,使用自訂比較函數呼叫 sort() 方法來按升序對數字進行排序,與預設排序演算法相比,可以獲得更好的效能。相反,壞範例依賴於預設排序演算法,這對於數值陣列可能不是最有效的。 - Node.js API 中的正確錯誤處理: ``` // Good: app.get('/user/:id', async (req, res) => { try { const user = await getUserById(req.params.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } res.json(user); } catch (error) { console.error('Error fetching user:', error); res.status(500).json({ error: 'Internal server error' }); } }); ``` ``` // Bad: app.get('/user/:id', async (req, res) => { const user = await getUserById(req.params.id); if (!user) { res.status(404).json({ error: 'User not found' }); } res.json(user); }); ``` 在 Node.js API 中,正確的錯誤處理對於確保穩健性和可靠性至關重要。在好的範例中,錯誤被捕獲並記錄,並且適當的 HTTP 狀態程式碼被返回到客戶端。相反,壞範例無法處理錯誤,可能導致未處理的承諾拒絕和不一致的錯誤回應。 - 高效率的檔案系統操作: ``` // Good: const fs = require('fs').promises; async function readFile(filePath) { try { const data = await fs.readFile(filePath, 'utf-8'); console.log(data); } catch (error) { console.error('Error reading file:', error); } } ``` ``` // Bad: const fs = require('fs'); function readFile(filePath) { fs.readFile(filePath, 'utf-8', (error, data) => { if (error) { console.error('Error reading file:', error); return; } console.log(data); }); } ``` 在檔案系統操作中使用 Promise 可以增強程式碼可讀性並簡化錯誤處理。在一個很好的範例中,fs.promises.readFile() 用於非同步讀取文件,並使用 try-catch 處理錯誤。相反,壞範例使用基於回調的方法,這可能導致回調地獄和可讀性較差的程式碼。 - 高效率的記憶體管理: ``` // Good: const stream = fs.createReadStream('bigfile.txt'); stream.pipe(response); ``` // 壞的: ``` fs.readFile('bigfile.txt', (error, data) => { if (error) { console.error('Error reading file:', error); return; } response.write(data); }); ``` 在 Node.js 中使用流進行大檔案處理可以節省記憶體並提高效能。在一個很好的例子中,fs.createReadStream() 和stream.pipe() 用於有效地將資料從檔案串流傳輸到HTTP 回應。相反,壞示例在將整個文件寫入響應之前將其讀入內存,這可能會導致大文件出現內存問題。 - 正確的模組導出和導入: ``` // Good: module.exports = { add: (a, b) => a + b, subtract: (a, b) => a - b }; ``` ``` // Bad: exports.add = (a, b) => a + b; exports.subtract = (a, b) => a - b; ``` 一致的模組導出和導入實踐提高了程式碼的可讀性和可維護性。在好的例子中, module.exports 用來匯出包含函數的物件,而在壞的例子中,直接使用exports。儘管這兩種方法都有效,但堅持一種約定可以增強程式碼的一致性。 - 非同步控制流程: ``` // Good: async function processItems(items) { for (const item of items) { await processItem(item); } } ``` ``` // Bad: function processItems(items) { items.forEach(item => { processItem(item); }); } ``` 適當的非同步控制流程可確保操作依需求順序或併發執行。在一個很好的範例中,非同步函數與 for...of 迴圈一起使用來順序處理專案,等待每個操作。相反,壞的例子使用了 forEach,它不能很好地處理非同步操作,並且可能會導致意外的行為。 --- 原文出處:https://dev.to/mahabubr/mastering-clean-code-essential-practices-for-developers-1287

掌握 JavaScript 生成器 🔥

JavaScript 是一種以其多功能性和易用性而聞名的語言,它具有多種功能,對於新手和經驗豐富的開發人員來說都非常強大。其中一項功能就是生成器。 ECMAScript 2015 (ES6) 中引入的生成器提供了一種處理迭代和非同步程式設計的獨特方法。在本文中,我們將探討什麼是生成器、它們如何運作以及它們的實際應用。 --- 什麼是 generator? ------- 生成器是一種特殊類型的函數,可以暫停和恢復執行。與呼叫時執行完成的常規函數不同,生成器在指定點將控制權交還給呼叫者。這種暫停和恢復的能力使它們對於需要一系列值或需要更優雅地處理非同步操作的任務特別有用。 --- 文法和基本用法 ------- 生成器函數是使用`function*`語法定義的,並使用`yield`關鍵字來暫停執行。 ``` function* myGenerator() { yield 1; yield 2; yield 3; } const gen = myGenerator(); console.log(gen.next()); // { value: 1, done: false } console.log(gen.next()); // { value: 2, done: false } console.log(gen.next()); // { value: 3, done: false } console.log(gen.next()); // { value: undefined, done: true } ``` 在此範例中, `myGenerator`是產生三個值的生成器函數。 `gen`物件是透過呼叫生成器函數所建立的迭代器。呼叫`gen.next()`傳回一個具有兩個屬性的物件: `value` (產生的值)和`done` (一個布林值,指示生成器是否已完成)。 --- `yield`的力量 ---------- `yield`關鍵字不僅暫停產生器,還允許將值傳回產生器。 ``` function* countingGenerator() { let count = 0; while (true) { count = yield count + 1; } } const counter = countingGenerator(); console.log(counter.next()); // { value: 1, done: false } console.log(counter.next(10)); // { value: 11, done: false } console.log(counter.next(20)); // { value: 21, done: false } ``` 在這裡,每次呼叫`counter.next()`都會恢復生成器,並且可以傳遞一個值來替換變數`count` 。這演示了生成器如何在暫停期間維護和更新其狀態。 --- 實際應用 ---- ### 📌 迭代 生成器在需要自訂迭代邏輯的場景中大放異彩。例如,您可以建立一個生成器來迭代一系列數字甚至複雜的資料結構。 ``` function* range(start, end) { for (let i = start; i <= end; i++) { yield i; } } for (const num of range(1, 5)) { console.log(num); // 1, 2, 3, 4, 5 } ``` --- ### 📌 非同步編程 生成器與 Promise 結合可以簡化非同步程式碼。像`co`這樣的函式庫使用這種模式比嵌套回呼或承諾鏈更自然地管理非同步流。 ``` const fetch = require('node-fetch'); function* fetchData(url) { const response = yield fetch(url); const data = yield response.json(); return data; } const co = require('co'); co(fetchData, 'https://api.example.com/data') .then(data => console.log(data)) .catch(err => console.error(err)); ``` --- ### 📌 無限序列 生成器可以建立無限序列,而由於陣列的有限性,這是不可能的。這在模擬、資料流或任何需要無限系列值的場景中非常有用。 ``` function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } } const fib = fibonacci(); console.log(fib.next().value); // 1 console.log(fib.next().value); // 1 console.log(fib.next().value); // 2 console.log(fib.next().value); // 3 console.log(fib.next().value); // 5 ``` --- 結論 -- JavaScript 中的生成器提供了一個強大的機制來處理序列、管理函數呼叫之間的狀態以及簡化非同步程式碼。 它們在 ES6 中的引入為該語言增添了顯著的靈活性和強大功能,使複雜的迭代和非同步模式變得更加平易近人。 隨著您深入研究 JavaScript,掌握生成器可以增強您編寫高效且可維護程式碼的能力。無論您是處理資料流、自訂迭代器還是非同步操作,生成器都提供了一個強大的工具來提升您的程式設計工具包。 --- ***快樂編碼!*** 🔥 **[領英](https://www.linkedin.com/in/dev-alisamir)** **[X(推特)](https://twitter.com/dev_alisamir)** **[電報](https://t.me/the_developer_guide)** **[Youtube](https://www.youtube.com/@DevGuideAcademy)** **[不和諧](https://discord.gg/s37uutmxT2)** **[Facebook](https://www.facebook.com/alisamir.dev)** **[Instagram](https://www.instagram.com/alisamir.dev)** --- 原文出處:https://dev.to/alisamirali/mastering-javascript-generators-15g3

我學習了 JavaScript 並製作了一款火爆網頁應用程式 🤯

隆重介紹**[Fakedin](https://fakedin-app.netlify.app/)** - 一款可以快速為社交媒體、簡報、迷因等建立令人驚嘆的假 LinkedIn 貼文的工具 🔥 請觀看下面的小演示影片,了解其工作原理,並存取該網站親自嘗試一下 🌟 --- https://www.youtube.com/watch?v=sikfunHdhRk --- 我必須承認,該應用程式還不完美,您可能會遇到一些錯誤,但不用擔心,我會在繼續進行時修復它們。目前,我正在尋求您的寶貴回饋,以使其變得更好。 🤝 **Fakedin 連結🔗** :https://fakedin-app.netlify.app/ 請務必檢查並分享您的回饋😇 感謝您的寶貴時間🙌 --- 另外,由於我每天發布的精彩內容,我最近在**[Linkedin](https://Linkedin.com/in/rammcodes)**上擁有了**14 萬**粉絲 ✌ 𝗙𝗼𝗹𝗹𝗼𝘄 我在**[Linkedin](https://Linkedin.com/in/rammcodes)**上取得與程式設計和 Web 開發相關的最精彩內容 💎 [![拉姆‧馬赫什瓦里 (Ram Maheshwari) (@rammcodes) Linkedin](https://i.postimg.cc/fL6k3xyT/www-linkedin-com-in-rammcodes-6.png)](https://Linkedin.com/in/rammcodes) --- 請用❤️🦄🤯🙌🔥 回覆這篇文章 &amp; 保存起來供以後使用🔖 --- 再一次感謝你 :) --- 原文出處:https://dev.to/rammcodes/i-learned-javascript-made-a-web-app-that-went-viral-3no0

只需 2GB 記憶體即可將後端擴展到 1M 請求 ⚡️

本部落格介紹了我如何解鎖效能,使我能夠在最少的資源(2 GB RAM 1v CPU 和最小網路頻寬 50-100 Mbps)上將後端從 50K 請求擴展到 1M 請求(~16K 請求/分鐘)。 ![迷因](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0m1kiuyq575f2qzyweu.png) 它將帶你踏上一段與過去的自己的旅程。這可能是一段漫長的旅程,所以請繫緊安全帶,享受這段旅程! 🎢 *它假設您熟悉後端和編寫 API。如果你了解一點 Go,這也是一個優勢。如果你不這樣做,也沒關係。您仍然可以按照我提供的資源來幫助您理解每個主題。 (如果您不知道 GO,這裡有一個*[*快速介紹*](https://www.youtube.com/watch?v=446E-r0rXHI)*)* 長話短說;博士, 首先,我們建立一個[可觀察性管道](https://www.observo.ai/post/what-is-an-observability-pipeline),幫助我們監控後端的所有面向。然後,我們開始對後端進行壓力測試,直到斷點測試(當一切最終崩潰時)。 →[連接輪詢以避免達到最大連接閾值](#optimization-1-connection-pooling-️) →[實施資源限制以避免非關鍵服務佔用資源](#optimization-2-unblocking-resources-from-alloy-open-telemetry-collector) →[新增索引](#optimization-3-adding-indexes-🏎️) →[禁用隱式事務](#optimization-4-ensure-while-testing-there-is-no-blocking-transaction) →[增加 Linux 的最大檔案描述符限制](#optimization-6-increasing-the-max-file-descriptor-limit) →[限制 Goroutines](#optimization-7-avoid-overloading-goroutines) →[未來計劃](#next-steps) 後端簡介🤝 ----- 讓我簡單介紹一下後端, - 它是一個用 Golang 寫的整體 RESTful API。 - 使用[GIN](https://github.com/gin-gonic/gin)框架編寫,並使用[GORM](https://gorm.io/)作為[ORM](https://www.theserverside.com/definition/object-relational-mapping-ORM) 。 - 使用 Aurora Postgres 作為託管在 AWS RDS 上的唯一主資料庫。 - 後端是[Docker 化的](https://dev.to/documatic/how-to-dockerize-your-application-536i#:~:text=Dockerizing%20an%20application%20is%20the,for%20developers%20and%20organizations%20alike.),我們在 AWS 上的`t2.small`實例中執行它。它具有 2GB RAM、50-100mb/s 網路頻寬、1 個 vCPU。 - 後端提供身份驗證、CRUD 操作、推播通知和即時更新。 - 對於即時更新,我們打開一個非常輕量級的[Web 套接字連接](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API),通知設備實體已更新。 我們的應用程式主要是讀取密集型,具有下降的寫入活動,如果我必須給它一個比率,它將是 65% 讀取/35% 寫入。 我可以寫一篇單獨的部落格來解釋我們為什麼選擇 - 整體架構、golang 或 postgress,但為了向您介紹[MsquareLabs 的](www.msquarelabs.com)tl;dr,我們相信「保持簡單,並建立允許我們以驚人的快節奏前進的程式碼。 資料資料資料🙊 ------- 在進行任何模擬負載生成之前,我首先將可觀察性建置到我們的後端中。其中包括追蹤、指標、分析和日誌。這使得找到問題並準確地找出造成疼痛的原因變得非常容易。當您對後端擁有如此強大的監控能力時,您也可以更輕鬆地更快地追蹤生產問題。 在我們繼續之前,讓我先簡單介紹一下指標、分析、日誌和追蹤: - 日誌:我們都知道日誌是什麼,它只是我們在事件發生時建立的大量文字訊息。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/94b2970c-34fc-4135-bed0-bf763ef098c8) - 追蹤:這是高度可見性的結構化日誌,有助於我們以正確的順序和時間封裝事件。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/9ee944e8-0637-4aa9-b076-5ff35990a8e2) - 指標:所有數字攪動資料,例如 CPU 使用率、活動請求和活動 goroutine。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/ec9a493d-6344-4c10-80e6-0db8c5c1d219) - 分析:為我們提供程式碼的即時指標及其對機器的影響,幫助我們了解正在發生的情況。 (WIP,下一篇部落格會詳細講) 要了解有關我如何將可觀察性建置到後端的更多訊息,您可以研究下一個博客(WIP),我將此部分移至另一個博客,因為我想避免讀者不知所措並只關註一件事 -**優化**) 這就是追蹤、日誌和指標的視覺化的樣子, ![截圖 2024-05-30 下午 4.53.29.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/20883b44-6f0f-42a1-b4f0-ae6ac2c04642) 所以現在我們有一個強大的監控管道+一個像樣的儀表板作為開始🚀 嘲笑高級用戶 x 100,000 🤺 ------------------ 現在真正的樂趣開始了,我們開始嘲笑愛上該應用程式的用戶。 「只有當你把你的愛(後端)置於極大的壓力時,你才會發現它的真正本質✨」 - 某個偉大的人,哈哈,idk Grafana 還提供了一個負載測試工具,因此我決定使用它,因為它只需要幾行程式碼的最少設置,因此您已經準備好了模擬服務。 我沒有觸及所有 API 路線,而是專注於最關鍵的路線,這些路線負責我們 90% 的流量。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/e42d706f-fc61-4cdd-8b0e-35113761f09c) 關於[k6](https://k6.io)的簡單介紹,它是一個基於 javascript 和 golang 的測試工具,您可以在其中快速定義要模擬的行為,它負責對其進行負載測試。無論您在主函數中定義什麼,都稱為*迭代*,k6 會啟動多個虛擬使用者單元(VU)來處理此迭代,直到達到給定的週期或迭代計數。 每次迭代構成4個請求,建立任務→更新任務→取得任務→刪除任務 ![iLoveIMG 下載 (1).jpg](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/32cb71fb-d549-48c9-88a0-ecaf48296593/c7dcc3cb-4128-44d4-b3ad-e736c96e377b) 慢慢開始,讓我們看看大約 10K 請求 → 100 VU 和 30 iter → 3000 iters x 4reqs → 12K 請求情況如何 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/84f31eec-79d5-49f9-915f-bb97b6d5f517) 這是輕而易舉的事情,沒有任何記憶體洩漏、CPU 過載或任何類型瓶頸的跡象,萬歲! 這是 k6 的摘要,發送了 13MB 資料,接收了 89MB,平均超過 52 req/s,平均延遲為 278ms,考慮到所有這些都在單台機器上執行,這還不錯。 ``` checks.........................: 100.00% ✓ 12001 ✗ 0 data_received..................: 89 MB 193 kB/s data_sent......................: 13 MB 27 kB/s http_req_blocked...............: avg=6.38ms min=0s med=6µs max=1.54s p(90)=11µs p(95)=14µs http_req_connecting............: avg=2.99ms min=0s med=0s max=536.44ms p(90)=0s p(95)=0s ✗ http_req_duration..............: avg=1.74s min=201.48ms med=278.15ms max=16.76s p(90)=9.05s p(95)=13.76s { expected_response:true }...: avg=1.74s min=201.48ms med=278.15ms max=16.76s p(90)=9.05s p(95)=13.76s ✓ http_req_failed................: 0.00% ✓ 0 ✗ 24001 http_req_receiving.............: avg=11.21ms min=10µs med=94µs max=2.18s p(90)=294µs p(95)=2.04ms http_req_sending...............: avg=43.3µs min=3µs med=32µs max=13.16ms p(90)=67µs p(95)=78µs http_req_tls_handshaking.......: avg=3.32ms min=0s med=0s max=678.69ms p(90)=0s p(95)=0s http_req_waiting...............: avg=1.73s min=201.36ms med=278.04ms max=15.74s p(90)=8.99s p(95)=13.7s http_reqs......................: 24001 52.095672/s iteration_duration.............: avg=14.48s min=1.77s med=16.04s max=21.39s p(90)=17.31s p(95)=18.88s iterations.....................: 3000 6.511688/s vus............................: 1 min=0 max=100 vus_max........................: 100 min=100 max=100 running (07m40.7s), 000/100 VUs, 3000 complete and 0 interrupted iterations _10k_v_hits ✓ [======================================] 100 VUs 07m38.9s/20m0s 3000/3000 iters, 30 per VU ``` 讓我們增加 12K → 100K 請求,發送 66MB,接收 462MB,CPU 使用率峰值達到 60%,記憶體使用率達到 50%,執行需要 40 分鐘(平均 2500 個請求/分鐘) ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/838e351e-ac9e-47a1-af51-4f69f75f5de0) 一切看起來都很好,直到我在日誌中看到一些奇怪的東西,“::gorm: 連接太多::”,快速檢查RDS 指標,確認打開的連接已達到410,即最大打開連接的限制。它是由 Aurora Postgres 本身[根據實例的可用記憶體](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Managing.html#AuroraPostgreSQL.Managing.MaxConnections)設定的。 您可以透過以下方法檢查, `select * from pg_settings where name='max_connections';` ⇒ 410 Postgres 為每個連接產生一個進程,考慮到它會在新請求到來時打開一個新連接並且之前的查詢仍在執行,因此這是極其昂貴的。因此 postgress 對可以開啟的並發連線數進行了限制。一旦達到限制,它會阻止任何進一步連接資料庫的嘗試,以避免實例崩潰(這可能會導致資料遺失) ### 優化一:連接池⚡️ 連接池是一種管理資料庫連接的技術,它重用打開的連接並確保它不會超過閾值,如果客戶端請求連接並且超過最大連接限制,它會等待直到連接被釋放或拒絕該請求。 這裡有兩個選項,要么執行客戶端池,要么使用單獨的服務,例如[pgBouncer](pgbouncer.org) (充當代理)。當我們規模較大且我們有連接到相同資料庫的分散式架構時,pgBouncer 確實是一個更好的選擇。因此,為了簡單性和我們的核心價值觀,我們選擇繼續進行客戶端池化。 幸運的是,我們使用的 ORM GORM 支援連接池,但[在幕後使用資料庫/SQL](https://gorm.io/docs/connecting_to_the_database.html#Connection-Pool) (golang 標準套件)來處理它。 有一些非常簡單的方法可以處理這個問題, ``` configSQLDriver, err := db.DB() if err != nil { log.Fatal(err) } configSQLDriver.SetMaxIdleConns(300) configSQLDriver.SetMaxOpenConns(380) // kept a few connections as buffer for developers configSQLDriver.SetConnMaxIdleTime(30 * time.Minute) configSQLDriver.SetConnMaxLifetime(time.Hour) ``` - `SetMaxIdleConns` → 保留在記憶體中的最大空閒連接,以便我們可以重複使用它(有助於減少開啟連接的延遲和成本) - `SetConnMaxIdleTime` → 我們應該在記憶體中保留空閒連接的最長時間。 - `SetMaxOpenConns` → 與資料庫的最大開啟連接,因為我們在同一個 RDS 實例上執行兩個環境 - `SetConnMaxLifetime` → 任何連線保持開啟的最長時間 現在更進一步,500K 請求(4000 個請求/分鐘)和 20 分鐘伺服器崩潰💥,最後讓我們調查一下🔎 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/39787835-b83d-441a-a3aa-a3b9fb03fc26) 快速查看指標,然後砰! CPU 和記憶體使用量激增。 Alloy(開放遙測收集器)佔用了所有 CPU 和內存,而不是我們的 API 容器。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/e8e764e4-31ea-44fa-b930-1bd1746d131b) ### 優化二:合金資源解鎖(開放式遙測收集器) 我們在小型 t2 實例中執行三個容器, - API開發 - API 分期 - 合金 當我們將大量負載轉儲到 DEV 伺服器時,它開始以相同的速率產生日誌和跟踪,從而呈指數級增加 CPU 使用率和網路出口。 因此,確保合金容器不會超出資源限制並妨礙關鍵服務非常重要。 由於合金在 docker 容器內執行,因此更容易強制執行此約束, ``` resources: limits: cpus: '0.5' memory: 400M ``` 此外,這次日誌不為空,存在多個上下文取消錯誤 - 原因是請求逾時,並且連接突然關閉。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/ace0ce7e-990e-43ea-a871-dc18888e3968) 然後我檢查了延遲,這太瘋狂了 😲 經過一段時間後,平均延遲為 30 - 40 秒。多虧了跟踪,我現在可以準確地找出是什麼導致瞭如此巨大的延遲。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/04be9892-5791-4834-b418-e9f417c0781d) 我們在 GET 操作中的查詢非常慢,讓我們對查詢執行[`EXPLAIN ANALYZE`](https://www.postgresql.org/docs/current/sql-explain.html) , ![截圖 2024-06-11 9.55.10 PM.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/3cf82d23-53c5-4976-aacc-2fa0d6ab2353) LEFT JOIN 花了 14.6 秒,而 LIMIT 又花了 14.6 秒,我們如何優化它 - INDEXING ### 優化3:新增索引🏎️ 為`where`或`ordering`子句中常用的欄位新增索引可以將查詢效能提高五倍。在新增 LEFT JOIN 表和 ORDER 欄位的索引後,相同查詢花費了 50 毫秒。你能從**14.6 秒 ⇒ 50 毫秒**開始思考嗎? (但要注意盲目加入索引,會導致CREATE/UPDATE/DELETE慢死) 它還可以更快地釋放連接,並有助於提高處理巨大並發負載的整體能力。 ### 最佳化 4:確保測試時沒有阻塞 TRANSACTION 🤡 從技術上講不是優化而是修復,您應該記住這一點。當您進行壓力測試時,您的程式碼不會嘗試同時更新/刪除相同實體。 在檢查程式碼時,我發現了一個錯誤,該錯誤導致每次請求時都會對用戶實體進行更新,並且當在事務內執行每個更新呼叫時,這會建立一個鎖,幾乎所有更新呼叫都被以前的更新呼叫阻止。 僅此一項修復就將吞吐量提高至 2 倍。 ### 最佳化5:跳過 GORM 的隱式 TRANSACTION 🎭 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/ab40af5b-c0fd-4c18-9067-859df56c4ec0) 預設情況下,GORM 在事務中執行每個查詢,這會降低效能,因為我們擁有極其強大的事務機制,在關鍵區域丟失事務的機會幾乎是不可能的(除非他們是實習生🤣)。 我們有一個中間件可以在到達模型層之前建立事務,並且有一個集中函數來確保控制器層中該事務的提交/回滾。 透過停用此功能,我們可以獲得[至少約 30% 的效能提升](https://gorm.io/docs/transactions.html#Disable-Default-Transaction)。 “我們卡在每分鐘 4-5K 請求的原因是這個,我認為這是我的筆記型電腦網路頻寬的問題。” - 愚蠢的我 所有這些優化帶來了 5 倍的吞吐量增益 💪,現在光是我的筆記型電腦就可以每分鐘產生 12K-18K 請求的流量。 ![截圖 2024-06-12 7.20.27 PM.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/fd440164-255f-4a4d-8389-c14365472372) ### 百萬點次數🐉 最後,每分鐘 10k-13K 請求達到 100 萬次,大約需要 2 小時,本來應該早點完成,但隨著合金重新啟動(由於資源限制),所有指標都會隨之丟失。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/6561ab09-1eb6-4b6f-92f2-92b5b2818590) 令我驚訝的是,該時間段內的最大 CPU 使用率為 60%,而記憶體使用量僅為 150MB。 Golang 的效能如此之高且處理負載的能力如此出色,這真是太瘋狂了。它具有最小的記憶體佔用。就是愛上了 golang 💖 每個查詢需要 200-400 毫秒才能完成,下一步是找出為什麼需要這麼多時間,我的猜測是連接池和 IO 阻塞減慢了查詢速度。 平均延遲降至約 2 秒,但仍有很大改進空間。 隱式優化🕊️ ------ ### 優化6:增加最大檔案描述子限制🔋 當我們在 Linux 作業系統中執行後端時,我們打開的每個網路連線都會建立一個檔案描述符,預設為 Linux 將每個進程限制為 1024 個,這阻礙了它達到峰值效能。 當我們開啟多個 Web 套接字連線時,如果有大量並發流量,我們很容易就會達到此限制。 Docker compose 提供了一個很好的抽象, ``` ulimits: core: soft: -1 hard: -1 ``` ### 優化 7:避免 goroutine 過載 🤹 作為一個 Go 開發者,我們經常認為 Goroutine 是理所當然的,只是盲目地在 Goroutine 中執行許多非關鍵任務,我們在函數之前加入`go` ,然後忘記它的執行,但在極端情況下它可能會成為瓶頸。 為了確保它永遠不會成為我的瓶頸,對於經常在 goroutine 中執行的服務,我使用帶有 n-worker 的記憶體佇列來執行任務。 ![圖片.png](https://res.craft.do/user/full/66854ea9-b711-5e28-ddbd-8d28e1defc9f/doc/355f2532-e0ec-485f-97e2-472751298750/b00e6636-6b3f-472e-99fc-f6c66ee87186) 後續步驟🏃‍♀️ -------- ### 改進:從 t2 移動到 t3 或 t3a t2是老一代的AWS通用機器,而t3和t3a、t4g是新一代。它們是可突發的實例,與 t2 相比,它們為長時間的 CPU 使用提供更好的網路頻寬和更好的效能 了解突發實例, [AWS 引入了可突發執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances.html)類型,主要針對大多數時間不需要 100% CPU 的工作負載。因此,這些實例以基準效能 (20% - 30%) 運作。當您的實例不需要 CPU 時,他們會維護一個積分系統,它會累積積分。當 CPU 峰值發生時,它會使用該積分。這可以降低您的 AWS 運算成本和浪費。 t3a 將是一個值得堅持的好系列,因為它們的成本/效率比在可突發實例係列中好得多。 這是一個比較[t2 和 t3 的](https://www.cloudzero.com/advisor/t2-vs-t3/)不錯的部落格。 ### 改進:查詢 我們可以對查詢/模式進行許多改進來提高速度,其中一些是: - 在插入重型表中批量插入。 - 透過非規範化避免 LEFT JOIN - 快取層 - 著色和分區,但這要晚得多。 ### 改進:分析 釋放效能的下一步是啟用分析並弄清楚執行時到底發生了什麼。 ### 改進:斷點測試 為了發現我的伺服器的限制和容量,下一步是斷點測試。 ### 尾註👋 如果你讀到最後,你已經破解了,恭喜你🍻 這是我的第一篇博客,如果有不清楚的地方,或者您想更深入地了解該主題,請告訴我。在我的下一篇部落格中,我將深入研究分析,敬請關注。 您可以在[X](x.com/_rikenshah)上關注我,以獲取最新資訊:) --- 原文出處:https://dev.to/rikenshah/scaling-backend-to-1m-requests-with-just-2gb-ram-4m0c

如何使用 Ollama 和打開 WebUI 在本地執行 Llama 3

https://youtu.be/GT-Fwg124-I 我是 Llama 的忠實粉絲。 Meta 發布其 LLM 開源程式碼對整個科技界來說是一項淨收益,其寬鬆的許可證允許大多數中小型企業在幾乎沒有任何限制的情況下使用其 LLM(當然,在法律範圍內)。他們的最新版本是備受期待的 Llama 3。 Llama 3 有兩種大小:80 億和 700 億參數。這種模型經過大量文字資料的訓練,可用於各種任務,包括生成文字、翻譯語言、編寫不同類型的創意內容以及以資訊豐富的方式回答您的問題。 Meta 宣稱 Llama 3 是最好的開放模型之一,但它仍在開發中。這是與 Mistral 和 Gemma 相比的 8B 模型基準(根據 Meta)。 ![基準測試](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ax9r9z2w2zghv81grbh7.png) 這就引出了一個問題:作為一個普通人,我如何在我的電腦上本地執行這些模型? 開始使用 Ollama ----------- 這就是[奧拉瑪](https://ollama.com/)登場的地方! Ollama 是一款免費的開源應用程式,可讓您在自己的電腦上執行各種大型語言模型,包括 Llama 3,即使資源有限。 Ollama 利用了 llama.cpp 的效能提升,llama.cpp 是一個開源程式庫,旨在允許您以相對較低的硬體要求在本地執行 LLM。它還包括一種套件管理器,使您只需一個命令即可快速有效地下載和使用 LLM。 第一步是[安裝 Ollama](https://ollama.com/download) 。它支援所有 3 個主要作業系統,其中[Windows 是「預覽版」](https://ollama.com/blog/windows-preview) (更好的說法是「測試版」)。 安裝完成後,打開您的終端。在所有平台上,命令都是相同的。 ``` ollama run llama3 ``` 等待幾分鐘,它會下載並載入模型,然後開始聊天!它應該會帶您進入與此類似的聊天提示。 ``` ollama run llama3 >>> Who was the second president of the united states? The second President of the United States was John Adams. He served from 1797 to 1801, succeeding George Washington and being succeeded by Thomas Jefferson. >>> Who was the 30th? The 30th President of the United States was Calvin Coolidge! He served from August 2, 1923, to March 4, 1929. >>> /bye ``` 您可以在這個終端聊天中整天聊天,但是如果您想要更像 ChatGPT 的東西怎麼辦? 打開網頁介面 ------ Open WebUI 是一個可擴充的、自架的 UI,完全在[Docker](https://docs.docker.com/desktop/)內部運作。它可以與 Ollama 或其他 OpenAI 相容的 LLM 一起使用,例如 LiteLLM 或我自己的[Cloudflare Workers OpenAI API](https://github.com/chand1012/openai-cf-workers-ai) 。 假設您的電腦上已經執行了[Docker](https://docs.docker.com/desktop/)和 Ollama,[安裝](https://docs.openwebui.com/getting-started/#quick-start-with-docker-)非常簡單。 ``` docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main ``` 只要造訪 http://localhost:3000,建立帳戶,然後開始聊天! ![OpenWebUI 範例](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdi1d35zh09s78o8vqvb.png) 如果您之前沒有執行過 Llama 3,則必須先關閉一些模型才能開始聊天。最簡單的方法是點擊左下角您的名字後點擊設定圖示。 ![設定](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqyetksyn0y4a0p12ylu.png) 然後點擊模式左側的“模型”,然後貼上[Ollama 註冊表](https://ollama.com/models)中的模型名稱。以下是我推薦用於一般用途的一些模型。 - `llama3` - `mistral` - `llama2` ![機型設定頁面](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txc581jf4w3xszymjfbg.png) 奧拉馬 API ------- 如果您想將 Ollama 整合到您自己的專案中,Ollama 提供自己的 API 以及 OpenAI 相容 API。 API 會自動將本機儲存的 LLM 載入到記憶體中,執行推理,然後在一定的逾時後卸載。您必須先拉取您想要使用的任何模型,然後才能透過 API 執行模型,這可以透過命令列輕鬆完成。 ``` ollama pull mistral ``` ### 奧拉馬 API Ollama 有自己的 API,其中還有[一些用於 Javascript 和 Python 的 SDK](https://github.com/ollama/ollama?tab=readme-ov-file#libraries) 。 以下是如何使用 API 進行簡單的文字產生推理。 ``` curl http://localhost:11434/api/generate -d '{ "model": "mistral", "prompt":"Why is the sky blue?" }' ``` 以下是如何使用 API 進行聊天產生推論。 ``` curl http://localhost:11434/api/chat -d '{ "model": "mistral", "messages": [ { "role": "user", "content": "why is the sky blue?" } ] }' ``` 將`model`參數替換為您要使用的任何模型。請參閱[官方 API 文件](https://github.com/ollama/ollama/blob/main/docs/api.md)以取得更多資訊。 ### OpenAI 相容 API 您也可以使用 Ollama 作為 OpenAI 庫的替代品(取決於用例)。這是[他們文件](https://github.com/ollama/ollama/blob/main/docs/openai.md)中的一個範例。 ``` # Python from openai import OpenAI client = OpenAI( base_url='http://localhost:11434/v1/', # required but ignored api_key='ollama', ) chat_completion = client.chat.completions.create( messages=[ { 'role': 'user', 'content': 'Say this is a test', } ], model='mistral', ) ``` 這也適用於 JavaScript。 ``` // Javascript import OpenAI from 'openai' const openai = new OpenAI({ baseURL: 'http://localhost:11434/v1/', // required but ignored apiKey: 'ollama', }) const chatCompletion = await openai.chat.completions.create({ messages: [{ role: 'user', content: 'Say this is a test' }], model: 'llama2', }) ``` 結論 -- Meta 的 Llama 3 的發布及其大型語言模型 (LLM) 技術的開源標誌著技術社群的一個重要里程碑。現在,透過 Ollama 和 Open WebUI 等本地工具可以存取這些先進的模型,普通個人可以挖掘其巨大潛力來生成文字、翻譯語言、創作創意寫作等。此外,API 的可用性使開發人員能夠將 LLM 無縫整合到新專案或增強現有專案。最終,LLM 技術透過 Llama 3 等開源專案實現民主化,釋放了廣泛的創新可能性,並激發了科技業的創造力。 --- 原文出處:https://dev.to/timesurgelabs/how-to-run-llama-3-locally-with-ollama-and-open-webui-297d