検索
ホームページウェブフロントエンドjsチュートリアルストリーミングおよび動的データを使用した高度な React SSR テクニック

Advanced React SSR Techniques with Streaming and Dynamic Data

アプリケーションが成長するにつれて、課題も増加します。先を行くには、シームレスで高性能のユーザー エクスペリエンスを提供するために、高度な SSR テクニックを習得することが不可欠です。

前の記事で React プロジェクトでサーバー側レンダリングの基盤を構築したので、プロジェクトのスケーラビリティを維持し、サーバーからクライアントにデータを効率的にロードし、ハイドレーションの問題を解決するのに役立つ機能を共有できることを嬉しく思います。

目次

  • SSR のストリーミングとは
  • 遅延読み込みと SSR
  • 遅延読み込みによるストリーミングの実装
    • React コンポーネントを更新しています
    • ストリーミング用サーバーの更新
  • サーバーからクライアントへのデータ
    • サーバー上でデータを渡す
    • クライアントで環境変数を処理する
  • 水分補給の問題
    • シナリオ例
    • 水分補給の問題を解決する
  • 結論

SSRのストリーミングとは何ですか

サーバーサイド レンダリング (SSR) でのストリーミング は、ページ全体の準備が整うのを待つのではなく、サーバーが HTML ページの一部を生成時に分割してブラウザーに送信する手法です。届ける前に。これにより、ブラウザはコンテンツのレンダリングをすぐに開始できるようになり、読み込み時間とユーザーのパフォーマンスが向上します。

ストリーミングは次の場合に特に効果的です。

  • 大きなページ: HTML 全体の生成にかなりの時間がかかる可能性があります。
  • 動的コンテンツ: ページの一部が外部 API 呼び出しまたは動的に生成されたチャンクに依存する場合。
  • 高トラフィック アプリケーション: ピーク使用時のサーバーの負荷と遅延を軽減します。

ストリーミングは、従来の SSR と最新のクライアント側の対話性の間のギャップを埋め、ユーザーがパフォーマンスを犠牲にすることなく意味のあるコンテンツをより速く表示できるようにします。

遅延読み込みと SSR

遅延読み込み は、実際に必要になるまでコンポーネントまたはモジュールの読み込みを延期し、初期読み込み時間を短縮し、パフォーマンスを向上させる手法です。 SSR と組み合わせると、遅延読み込みはサーバーとクライアントの両方のワークロードを大幅に最適化できます。

遅延読み込みは、コンポーネントを Promise として動的にインポートする React.lazy に依存しています。従来の SSR では、レンダリングは同期的です。つまり、サーバーは完全な HTML を生成してブラウザに送信する前に、すべての Promises を解決する必要があります。

ストリーミングは、コンポーネントがレンダリングされるときにサーバーが HTML をチャンクで送信できるようにすることで、これらの課題を解決します。このアプローチにより、サスペンス フォールバックをブラウザーに即座に送信できるようになり、ユーザーが意味のあるコンテンツを早期に確認できるようになります。遅延ロードされたコンポーネントが解決されると、レンダリングされた HTML が段階的にブラウザにストリーミングされ、フォールバック コンテンツがシームレスに置き換えられます。これにより、レンダリング プロセスのブロックが回避され、遅延が減少し、体感的な読み込み時間が短縮されます。

遅延読み込みによるストリーミングの実装

このガイドは、下部にリンクされている前の記事 本番対応 SSR React アプリケーションの構築 で紹介した概念に基づいて構築されています。 React で SSR を有効にし、遅延読み込みコンポーネントをサポートするために、React コンポーネントとサーバーの両方にいくつかの更新を加えます。

React コンポーネントの更新

サーバーエントリーポイント

React の renderToString メソッドは SSR によく使用されますが、HTML コンテンツ全体の準備が整うまで待ってからブラウザに送信します。 renderToPipeableStream に切り替えることで、生成された HTML の一部を送信するストリーミングを有効にすることができます。

// ./src/entry-server.tsx
import { renderToPipeableStream, RenderToPipeableStreamOptions } from 'react-dom/server'
import App from './App'

export function render(options?: RenderToPipeableStreamOptions) {
  return renderToPipeableStream(<app></app>, options)
}

遅延ロードコンポーネントの作成

この例では、概念を示すために単純な Card コンポーネントを作成します。運用アプリケーションでは、この手法は通常、パフォーマンスを最適化するために、より大きなモジュールまたはページ全体で使用されます。

// ./src/Card.tsx
import { useState } from 'react'

function Card() {
  const [count, setCount] = useState(0)

  return (
    <div classname="card">
      <button onclick="{()"> setCount((count) => count + 1)}>
        count is {count}
      </button>
      <p>
        Edit <code>src/App.tsx</code> and save to test HMR
      </p>
    </div>
  )
}

export default Card

アプリでの遅延ロードコンポーネントの使用

遅延読み込みコンポーネントを使用するには、React.lazy を使用してコンポーネントを動的にインポートし、Suspense でラップして読み込み中にフォールバック UI を提供します

// ./src/App.tsx
import { lazy, Suspense } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

const Card = lazy(() => import('./Card'))

function App() {
  return (
    
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src="%7BviteLogo%7D" classname="logo" alt="Vite logo">
        </a>
        <a href="https://react.dev" target="_blank">
          <img src="%7BreactLogo%7D" classname="logo react" alt="React logo">
        </a>
      </div>
      <h1 id="Vite-React">Vite + React</h1>
      <suspense fallback="Loading...">
        <card></card>
      </suspense>
      <p classname="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    >
  )
}

export default App

ストリーミング用にサーバーを更新する

ストリーミングを有効にするには、開発セットアップと運用セットアップの両方が一貫した HTML レンダリング プロセスをサポートする必要があります。どちらの環境でもプロセスは同じであるため、単一の再利用可能な関数を作成して、ストリーミング コンテンツを効果的に処理できます。

ストリームコンテンツ関数の作成

// ./server/constants.ts
export const ABORT_DELAY = 5000

streamContent 関数は、レンダリング プロセスを開始し、HTML の増分チャンクを応答に書き込み、適切なエラー処理を保証します。

// ./server/streamContent.ts
import { Transform } from 'node:stream'
import { Request, Response, NextFunction } from 'express'
import { ABORT_DELAY, HTML_KEY } from './constants'
import type { render } from '../src/entry-server'

export type StreamContentArgs = {
  render: typeof render
  html: string
  req: Request
  res: Response
  next: NextFunction
}

export function streamContent({ render, html, res }: StreamContentArgs) {
  let renderFailed = false

  // Initiates the streaming process by calling the render function
  const { pipe, abort } = render({
    // Handles errors that occur before the shell is ready
    onShellError() {
      res.status(500).set({ 'Content-Type': 'text/html' }).send('<pre class="brush:php;toolbar:false">Something went wrong
') }, // Called when the shell (initial HTML) is ready for streaming onShellReady() { res.status(renderFailed ? 500 : 200).set({ 'Content-Type': 'text/html' }) // Split the HTML into two parts using the placeholder const [htmlStart, htmlEnd] = html.split(HTML_KEY) // Write the starting part of the HTML to the response res.write(htmlStart) // Create a transform stream to handle the chunks of HTML from the renderer const transformStream = new Transform({ transform(chunk, encoding, callback) { // Write each chunk to the response res.write(chunk, encoding) callback() }, }) // When the streaming is finished, write the closing part of the HTML transformStream.on('finish', () => { res.end(htmlEnd) }) // Pipe the render output through the transform stream pipe(transformStream) }, onError(error) { // Logs errors encountered during rendering renderFailed = true console.error((error as Error).stack) }, }) // Abort the rendering process after a delay to avoid hanging requests setTimeout(abort, ABORT_DELAY) }

開発構成の更新

// ./server/dev.ts
import { Application } from 'express'
import fs from 'fs'
import path from 'path'
import { StreamContentArgs } from './streamContent'

const HTML_PATH = path.resolve(process.cwd(), 'index.html')
const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'src/entry-server.tsx')

// Add to args the streamContent callback
export async function setupDev(app: Application, streamContent: (args: StreamContentArgs) => void) {
  const vite = await (
    await import('vite')
  ).createServer({
    root: process.cwd(),
    server: { middlewareMode: true },
    appType: 'custom',
  })

  app.use(vite.middlewares)

  app.get('*', async (req, res, next) => {
    try {
      let html = fs.readFileSync(HTML_PATH, 'utf-8')
      html = await vite.transformIndexHtml(req.originalUrl, html)

      const { render } = await vite.ssrLoadModule(ENTRY_SERVER_PATH)

      // Use the same callback for production and development process
      streamContent({ render, html, req, res, next })
    } catch (e) {
      vite.ssrFixStacktrace(e as Error)
      console.error((e as Error).stack)
      next(e)
    }
  })
}

実稼働構成の更新

// ./server/prod.ts
import { Application } from 'express'
import fs from 'fs'
import path from 'path'
import compression from 'compression'
import sirv from 'sirv'
import { StreamContentArgs } from './streamContent'

const CLIENT_PATH = path.resolve(process.cwd(), 'dist/client')
const HTML_PATH = path.resolve(process.cwd(), 'dist/client/index.html')
const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'dist/ssr/entry-server.js')

// Add to Args the streamContent callback
export async function setupProd(app: Application, streamContent: (args: StreamContentArgs) => void) {
  app.use(compression())
  app.use(sirv(CLIENT_PATH, { extensions: [] }))

  app.get('*', async (req, res, next) => {
    try {
      const html = fs.readFileSync(HTML_PATH, 'utf-8')

      const { render } = await import(ENTRY_SERVER_PATH)

      // Use the same callback for production and development process
      streamContent({ render, html, req, res, next })
    } catch (e) {
      console.error((e as Error).stack)
      next(e)
    }
  })
}

Express サーバーの更新

streamContent 関数を各構成に渡します:

// ./server/app.ts
import express from 'express'
import { PROD, APP_PORT } from './constants'
import { setupProd } from './prod'
import { setupDev } from './dev'
import { streamContent } from './streamContent'

export async function createServer() {
  const app = express()

  if (PROD) {
    await setupProd(app, streamContent)
  } else {
    await setupDev(app, streamContent)
  }

  app.listen(APP_PORT, () => {
    console.log(`http://localhost:${APP_PORT}`)
  })
}

createServer()

これらの変更を実装すると、サーバーは次のようになります:

  • HTML を段階的にブラウザにストリーミングし、最初の描画にかかる時間を短縮します。
  • 遅延ロードされたコンポーネントをシームレスに処理し、パフォーマンスとユーザー エクスペリエンスの両方を向上させます。

サーバーからクライアントへのデータ

HTML をクライアントに送信する前に、サーバーで生成された HTML を完全に制御できます。これにより、必要に応じてタグ、スタイル、リンク、またはその他の要素を追加して、構造を動的に変更できます。

特に強力な手法の 1 つは、<script> を挿入することです。タグを HTML に追加します。このアプローチにより、動的データをクライアントに直接渡すことができます。</script>

この例では、環境変数を渡すことに焦点を当てますが、必要な JavaScript オブジェクトを渡すこともできます。環境変数をクライアントに渡すことで、それらの変数が変更されたときにアプリケーション全体を再構築する必要がなくなります。下部にリンクされているサンプル リポジトリでは、プロファイル データがどのように動的に渡されるかを確認することもできます。

サーバー上でデータを渡す

API_URL を定義する

サーバーに API_URL 環境変数を設定します。デフォルトでは、これは jsonplaceholder を指します。 __INITIAL_DATA__ は、グローバル ウィンドウ オブジェクトにデータを保存するためのキーとして機能します。

// ./src/entry-server.tsx
import { renderToPipeableStream, RenderToPipeableStreamOptions } from 'react-dom/server'
import App from './App'

export function render(options?: RenderToPipeableStreamOptions) {
  return renderToPipeableStream(<app></app>, options)
}

初期データを HTML に挿入する

クライアントに送信する前に、初期データを HTML 文字列に挿入するユーティリティ関数を作成します。このデータには、API_URL などの環境変数が含まれます。

// ./src/Card.tsx
import { useState } from 'react'

function Card() {
  const [count, setCount] = useState(0)

  return (
    <div classname="card">
      <button onclick="{()"> setCount((count) => count + 1)}>
        count is {count}
      </button>
      <p>
        Edit <code>src/App.tsx</code> and save to test HMR
      </p>
    </div>
  )
}

export default Card

ストリームコンテンツを更新する

applyInitialData 関数を使用して、初期データを HTML に挿入し、クライアントに送信します。

// ./src/App.tsx
import { lazy, Suspense } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

const Card = lazy(() => import('./Card'))

function App() {
  return (
    
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src="%7BviteLogo%7D" classname="logo" alt="Vite logo">
        </a>
        <a href="https://react.dev" target="_blank">
          <img src="%7BreactLogo%7D" classname="logo react" alt="React logo">
        </a>
      </div>
      <h1 id="Vite-React">Vite + React</h1>
      <suspense fallback="Loading...">
        <card></card>
      </suspense>
      <p classname="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    >
  )
}

export default App

クライアント上で環境変数を処理する

グローバルウィンドウを拡張するタイプ

グローバル型宣言を更新して、__INITIAL_DATA__ キーとその構造を含めます。

// ./server/constants.ts
export const ABORT_DELAY = 5000

WindowオブジェクトからAPI_URLにアクセスする

// ./server/streamContent.ts
import { Transform } from 'node:stream'
import { Request, Response, NextFunction } from 'express'
import { ABORT_DELAY, HTML_KEY } from './constants'
import type { render } from '../src/entry-server'

export type StreamContentArgs = {
  render: typeof render
  html: string
  req: Request
  res: Response
  next: NextFunction
}

export function streamContent({ render, html, res }: StreamContentArgs) {
  let renderFailed = false

  // Initiates the streaming process by calling the render function
  const { pipe, abort } = render({
    // Handles errors that occur before the shell is ready
    onShellError() {
      res.status(500).set({ 'Content-Type': 'text/html' }).send('<pre class="brush:php;toolbar:false">Something went wrong
') }, // Called when the shell (initial HTML) is ready for streaming onShellReady() { res.status(renderFailed ? 500 : 200).set({ 'Content-Type': 'text/html' }) // Split the HTML into two parts using the placeholder const [htmlStart, htmlEnd] = html.split(HTML_KEY) // Write the starting part of the HTML to the response res.write(htmlStart) // Create a transform stream to handle the chunks of HTML from the renderer const transformStream = new Transform({ transform(chunk, encoding, callback) { // Write each chunk to the response res.write(chunk, encoding) callback() }, }) // When the streaming is finished, write the closing part of the HTML transformStream.on('finish', () => { res.end(htmlEnd) }) // Pipe the render output through the transform stream pipe(transformStream) }, onError(error) { // Logs errors encountered during rendering renderFailed = true console.error((error as Error).stack) }, }) // Abort the rendering process after a delay to avoid hanging requests setTimeout(abort, ABORT_DELAY) }

動的 API_URL を使用してリクエストを作成する

// ./server/dev.ts
import { Application } from 'express'
import fs from 'fs'
import path from 'path'
import { StreamContentArgs } from './streamContent'

const HTML_PATH = path.resolve(process.cwd(), 'index.html')
const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'src/entry-server.tsx')

// Add to args the streamContent callback
export async function setupDev(app: Application, streamContent: (args: StreamContentArgs) => void) {
  const vite = await (
    await import('vite')
  ).createServer({
    root: process.cwd(),
    server: { middlewareMode: true },
    appType: 'custom',
  })

  app.use(vite.middlewares)

  app.get('*', async (req, res, next) => {
    try {
      let html = fs.readFileSync(HTML_PATH, 'utf-8')
      html = await vite.transformIndexHtml(req.originalUrl, html)

      const { render } = await vite.ssrLoadModule(ENTRY_SERVER_PATH)

      // Use the same callback for production and development process
      streamContent({ render, html, req, res, next })
    } catch (e) {
      vite.ssrFixStacktrace(e as Error)
      console.error((e as Error).stack)
      next(e)
    }
  })
}

これで、クライアント側のコードで動的な環境変数を使用できるようになり、JavaScript バンドルを再構築せずにサーバーからクライアントへのデータを管理できるようになりました。このアプローチにより構成が簡素化され、アプリの柔軟性と拡張性が向上します。

水分補給の問題

サーバーからクライアントにデータを渡すことができるようになったので、このデータをコンポーネント内で直接使用しようとすると、ハイドレーションの問題が発生する可能性があります。これらのエラーは、サーバーでレンダリングされた HTML がクライアントでの最初の React レンダリングと一致しないために発生します。

シナリオ例

コンポーネント内で API_URL を単純な文字列として使用することを検討してください

// ./src/entry-server.tsx
import { renderToPipeableStream, RenderToPipeableStreamOptions } from 'react-dom/server'
import App from './App'

export function render(options?: RenderToPipeableStreamOptions) {
  return renderToPipeableStream(<app></app>, options)
}

この場合、サーバーは API_URL を空の文字列としてコンポーネントをレンダリングしますが、クライアントでは API_URL にすでにウィンドウ オブジェクトの値が含まれています。 React はサーバーでレンダリングされた HTML とクライアントの React ツリーの間の差異を検出するため、この不一致によりハイドレーション エラーが発生します。

ユーザーにはコンテンツがすぐに更新されることがわかりますが、React はコンソールにハイドレーション警告を記録します。この問題を解決するには、サーバーとクライアントが同じ初期 HTML をレンダリングするか、API_URL をサーバーのエントリ ポイントに明示的に渡す必要があります。

水分補給の問題を解決する

エラーを解決するには、サーバー エントリ ポイントを介して、initialData をアプリ コンポーネントに渡します。

ストリームコンテンツを更新する

// ./src/Card.tsx
import { useState } from 'react'

function Card() {
  const [count, setCount] = useState(0)

  return (
    <div classname="card">
      <button onclick="{()"> setCount((count) => count + 1)}>
        count is {count}
      </button>
      <p>
        Edit <code>src/App.tsx</code> and save to test HMR
      </p>
    </div>
  )
}

export default Card

レンダリング関数でのデータの処理

// ./src/App.tsx
import { lazy, Suspense } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

const Card = lazy(() => import('./Card'))

function App() {
  return (
    
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src="%7BviteLogo%7D" classname="logo" alt="Vite logo">
        </a>
        <a href="https://react.dev" target="_blank">
          <img src="%7BreactLogo%7D" classname="logo react" alt="React logo">
        </a>
      </div>
      <h1 id="Vite-React">Vite + React</h1>
      <suspense fallback="Loading...">
        <card></card>
      </suspense>
      <p classname="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    >
  )
}

export default App

アプリコンポーネントでinitialDataを使用する

// ./server/constants.ts
export const ABORT_DELAY = 5000

これで、サーバーでレンダリングされた HTML がクライアントでの最初の React レンダリングと一致し、ハイドレーション エラーがなくなりました。 React はサーバーとクライアントのツリーを正しく調整し、シームレスなエクスペリエンスを保証します。

API_URL のような動的データの場合は、React Context を使用してサーバーとクライアントの間でデフォルト値を管理し、渡すことを検討してください。このアプローチにより、コンポーネント間での共有データの管理が簡素化されます。実装例は、リンクされたリポジトリの下部にあります。

結論

この記事では、ストリーミングの実装、サーバーからクライアントへのデータの管理、ハイドレーションの問題の解決に焦点を当てて、React の高度な SSR テクニックを検討しました。これらの方法により、アプリケーションのスケーラビリティとパフォーマンスが向上し、シームレスなユーザー エクスペリエンスが実現されます。

コードを探索する

  • : 反応-ssr-高度な例
  • テンプレート: 反応-ssr-ストリーミング-テンプレート
  • Vite Extra テンプレート: template-ssr-react-streaming-ts

関連記事

これは、React を使用した SSR に関するシリーズの一部です。他の記事もお楽しみに!

  • 本番環境に対応した SSR React アプリケーションを構築する
  • ストリーミングと動的データを使用した高度な React SSR テクニック (ここにいます)
  • SSR React アプリケーションでのテーマのセットアップ (近日公開予定)

つながりを保つ

フィードバック、コラボレーション、技術的なアイデアについての議論はいつでも受け付けています。お気軽にご連絡ください。

  • ポートフォリオ: maxh1t.xyz
  • メール: m4xh17@gmail.com

以上がストリーミングおよび動的データを使用した高度な React SSR テクニックの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScriptのデータ型:ブラウザとNodejsに違いはありますか?JavaScriptのデータ型:ブラウザとNodejsに違いはありますか?May 14, 2025 am 12:15 AM

JavaScriptコアデータ型は、ブラウザとnode.jsで一貫していますが、余分なタイプとは異なる方法で処理されます。 1)グローバルオブジェクトはブラウザのウィンドウであり、node.jsのグローバルです2)バイナリデータの処理に使用されるNode.jsの一意のバッファオブジェクト。 3)パフォーマンスと時間の処理にも違いがあり、環境に従ってコードを調整する必要があります。

JavaScriptコメント://および / * *を使用するためのガイドJavaScriptコメント://および / * *を使用するためのガイドMay 13, 2025 pm 03:49 PM

javascriptusestwotypesofcomments:シングルライン(//)およびマルチライン(//)

Python vs. JavaScript:開発者の比較分析Python vs. JavaScript:開発者の比較分析May 09, 2025 am 12:22 AM

PythonとJavaScriptの主な違いは、タイプシステムとアプリケーションシナリオです。 1。Pythonは、科学的コンピューティングとデータ分析に適した動的タイプを使用します。 2。JavaScriptは弱いタイプを採用し、フロントエンドとフルスタックの開発で広く使用されています。この2つは、非同期プログラミングとパフォーマンスの最適化に独自の利点があり、選択する際にプロジェクトの要件に従って決定する必要があります。

Python vs. JavaScript:ジョブに適したツールを選択するPython vs. JavaScript:ジョブに適したツールを選択するMay 08, 2025 am 12:10 AM

PythonまたはJavaScriptを選択するかどうかは、プロジェクトの種類によって異なります。1)データサイエンスおよび自動化タスクのPythonを選択します。 2)フロントエンドとフルスタック開発のためにJavaScriptを選択します。 Pythonは、データ処理と自動化における強力なライブラリに好まれていますが、JavaScriptはWebインタラクションとフルスタック開発の利点に不可欠です。

PythonとJavaScript:それぞれの強みを理解するPythonとJavaScript:それぞれの強みを理解するMay 06, 2025 am 12:15 AM

PythonとJavaScriptにはそれぞれ独自の利点があり、選択はプロジェクトのニーズと個人的な好みに依存します。 1. Pythonは、データサイエンスやバックエンド開発に適した簡潔な構文を備えた学習が簡単ですが、実行速度が遅くなっています。 2。JavaScriptはフロントエンド開発のいたるところにあり、強力な非同期プログラミング機能を備えています。 node.jsはフルスタックの開発に適していますが、構文は複雑でエラーが発生しやすい場合があります。

JavaScriptのコア:CまたはCの上に構築されていますか?JavaScriptのコア:CまたはCの上に構築されていますか?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc;それは、解釈されていることを解釈しました。

JavaScriptアプリケーション:フロントエンドからバックエンドまでJavaScriptアプリケーション:フロントエンドからバックエンドまでMay 04, 2025 am 12:12 AM

JavaScriptは、フロントエンドおよびバックエンド開発に使用できます。フロントエンドは、DOM操作を介してユーザーエクスペリエンスを強化し、バックエンドはnode.jsを介してサーバータスクを処理することを処理します。 1.フロントエンドの例:Webページテキストのコンテンツを変更します。 2。バックエンドの例:node.jsサーバーを作成します。

Python vs. Javascript:どの言語を学ぶべきですか?Python vs. Javascript:どの言語を学ぶべきですか?May 03, 2025 am 12:10 AM

PythonまたはJavaScriptの選択は、キャリア開発、学習曲線、エコシステムに基づいている必要があります。1)キャリア開発:Pythonはデータサイエンスとバックエンド開発に適していますが、JavaScriptはフロントエンドおよびフルスタック開発に適しています。 2)学習曲線:Python構文は簡潔で初心者に適しています。 JavaScriptの構文は柔軟です。 3)エコシステム:Pythonには豊富な科学コンピューティングライブラリがあり、JavaScriptには強力なフロントエンドフレームワークがあります。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、