最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端JS大文件上傳失敗問(wèn)題深度解析和完美解決方案

 更新時(shí)間:2025年11月26日 08:36:49   作者:碼農(nóng)阿豪@新空間  
在當(dāng)今數(shù)字化時(shí)代,視頻內(nèi)容已成為信息傳遞的主要載體,我們經(jīng)常需要處理各種大小的視頻文件,本文將通過(guò)一個(gè)真實(shí)的技術(shù)支持案例,深入分析大文件上傳過(guò)程中的各種陷阱,并提供從基礎(chǔ)到高級(jí)的完整解決方案,大家可以根據(jù)需要進(jìn)行選擇

引言:數(shù)字時(shí)代的大文件挑戰(zhàn)

在當(dāng)今數(shù)字化時(shí)代,視頻內(nèi)容已成為信息傳遞的主要載體。從短視頻應(yīng)用到在線教育平臺(tái),從企業(yè)培訓(xùn)到個(gè)人創(chuàng)作,我們經(jīng)常需要處理各種大小的視頻文件。然而,許多開發(fā)者和用戶在嘗試上傳較大視頻文件時(shí),都會(huì)遇到一個(gè)令人頭疼的問(wèn)題:“小文件順利上傳,大文件卻莫名失敗”。

本文將通過(guò)一個(gè)真實(shí)的技術(shù)支持案例,深入分析大文件上傳過(guò)程中的各種陷阱,并提供從基礎(chǔ)到高級(jí)的完整解決方案。無(wú)論你是前端開發(fā)者、后端工程師還是運(yùn)維人員,都能從中找到應(yīng)對(duì)大文件上傳挑戰(zhàn)的有效策略。

問(wèn)題現(xiàn)象:連接重置錯(cuò)誤的背后

錯(cuò)誤場(chǎng)景還原

讓我們先來(lái)看一個(gè)典型的錯(cuò)誤場(chǎng)景。用戶在使用視頻切割工具時(shí),小視頻文件能夠正常處理,但當(dāng)嘗試上傳較大的視頻文件(如教學(xué)視頻、錄制會(huì)議等)時(shí),控制臺(tái)出現(xiàn)了以下錯(cuò)誤:

POST http://43.143.48.239/prod-api/toolbox/video/split net::ERR_CONNECTION_RESET

這個(gè)ERR_CONNECTION_RESET錯(cuò)誤表明在文件上傳過(guò)程中,TCP連接被意外重置。就像在郵寄包裹時(shí),小包裹能順利送達(dá),但大包裹卻在運(yùn)輸途中被退回,且沒(méi)有明確的退回理由。

伴隨的警告信息

同時(shí),控制臺(tái)還出現(xiàn)了另一個(gè)警告:

[Violation] Added non-passive event listener to a scroll-blocking 'touchmove' event.

這個(gè)警告雖然不直接導(dǎo)致上傳失敗,但它暗示了前端代碼中可能存在性能問(wèn)題,在處理大文件時(shí)這些問(wèn)題會(huì)被放大。

根本原因分析:多維度問(wèn)題排查

1. 服務(wù)器配置限制

服務(wù)器通常會(huì)對(duì)文件上傳設(shè)置各種限制,這是最常見的問(wèn)題根源:

Nginx 配置限制:

# nginx.conf 中的常見限制配置
http {
    client_max_body_size 10m;  # 默認(rèn)通常為1MB
    client_body_timeout 60s;   # 請(qǐng)求體超時(shí)時(shí)間
    proxy_read_timeout 60s;    # 代理讀取超時(shí)
}

后端應(yīng)用限制:

  • Spring Boot(Java):spring.servlet.multipart.max-file-size=10MB
  • Express(Node.js):bodyParser.json({limit: '10mb'})
  • Django(Python):DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760

2. 網(wǎng)絡(luò)環(huán)境不穩(wěn)定

大文件上傳對(duì)網(wǎng)絡(luò)穩(wěn)定性要求極高:

  • 網(wǎng)絡(luò)抖動(dòng):即使短暫的網(wǎng)絡(luò)中斷也會(huì)導(dǎo)致上傳失敗
  • 代理服務(wù)器限制:企業(yè)網(wǎng)絡(luò)中的代理服務(wù)器可能有自己的大小限制
  • 防火墻策略:某些安全策略會(huì)限制長(zhǎng)時(shí)間連接

3. 前端超時(shí)設(shè)置

默認(rèn)情況下,前端請(qǐng)求沒(méi)有設(shè)置合理的超時(shí)時(shí)間:

// 默認(rèn)的axios請(qǐng)求沒(méi)有超時(shí)設(shè)置
axios.post('/upload', formData); // 風(fēng)險(xiǎn):可能永遠(yuǎn)掛起

// 或者使用默認(rèn)的短超時(shí)
fetch('/upload', { method: 'POST', body: formData }); // 默認(rèn)超時(shí)可能只有30秒

4. 瀏覽器內(nèi)存限制

處理大文件時(shí),前端JavaScript可能遇到內(nèi)存限制:

  • 單個(gè)File對(duì)象過(guò)大導(dǎo)致內(nèi)存溢出
  • Base64編碼消耗更多內(nèi)存
  • 進(jìn)度追蹤數(shù)據(jù)結(jié)構(gòu)過(guò)于復(fù)雜

全面解決方案:從基礎(chǔ)到高級(jí)

方案一:基礎(chǔ)配置優(yōu)化

前端超時(shí)優(yōu)化

// 全面的axios配置
const uploadAPI = axios.create({
  baseURL: '/prod-api',
  timeout: 600000, // 10分鐘超時(shí)
  headers: {
    'Content-Type': 'multipart/form-data'
  }
});

// 帶進(jìn)度監(jiān)控的上傳函數(shù)
async function uploadWithProgress(file, onProgress) {
  const formData = new FormData();
  formData.append('file', file);
  formData.append('splitDuration', 10);
  
  try {
    const response = await uploadAPI.post('/toolbox/video/split', formData, {
      onUploadProgress: (progressEvent) => {
        if (onProgress && progressEvent.total) {
          const percent = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          );
          onProgress(percent);
        }
      },
      // 重試配置
      retry: 3,
      retryDelay: 1000
    });
    return response.data;
  } catch (error) {
    console.error('上傳失敗:', error);
    throw error;
  }
}

服務(wù)器配置優(yōu)化

Nginx 優(yōu)化配置:

server {
    listen 80;
    server_name your-domain.com;
    
    # 文件上傳大小限制(調(diào)整為100M)
    client_max_body_size 100m;
    
    # 超時(shí)時(shí)間設(shè)置
    client_body_timeout 300s;
    client_header_timeout 300s;
    keepalive_timeout 300s;
    send_timeout 300s;
    
    # 代理設(shè)置
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    location /prod-api/ {
        proxy_pass http://backend-server;
        # 禁用緩沖,支持直接流式傳輸
        proxy_request_buffering off;
    }
}

方案二:分片上傳 - 最可靠的解決方案

分片上傳是將大文件分割成多個(gè)小塊分別上傳的技術(shù),具有以下優(yōu)勢(shì):

  • 避免單次請(qǐng)求過(guò)大
  • 支持?jǐn)帱c(diǎn)續(xù)傳
  • 更好的進(jìn)度反饋
  • 更高的成功率

完整的分片上傳實(shí)現(xiàn)

前端分片上傳組件:

class ChunkedUploader {
  constructor(options = {}) {
    this.chunkSize = options.chunkSize || 5 * 1024 * 1024; // 5MB默認(rèn)分片大小
    this.retryCount = options.retryCount || 3;
    this.concurrentUploads = options.concurrentUploads || 3;
    this.onProgress = options.onProgress || (() => {});
    this.onComplete = options.onComplete || (() => {});
    this.onError = options.onError || (() => {});
  }

  // 生成文件唯一標(biāo)識(shí)
  async generateFileHash(file) {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        // 簡(jiǎn)單的哈希生成,實(shí)際項(xiàng)目可使用更復(fù)雜的算法
        const arrayBuffer = e.target.result;
        const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
        const hash = CryptoJS.MD5(wordArray).toString();
        resolve(hash);
      };
      reader.readAsArrayBuffer(file.slice(0, 1024)); // 只讀取前1KB用于生成哈希
    });
  }

  // 上傳單個(gè)分片
  async uploadChunk(fileHash, chunk, chunkIndex, totalChunks, fileName) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('chunkIndex', chunkIndex);
    formData.append('totalChunks', totalChunks);
    formData.append('fileHash', fileHash);
    formData.append('fileName', fileName);

    for (let attempt = 1; attempt <= this.retryCount; attempt++) {
      try {
        const response = await axios.post('/toolbox/video/chunk-upload', formData, {
          timeout: 60000,
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        });
        return response.data;
      } catch (error) {
        if (attempt === this.retryCount) {
          throw new Error(`分片 ${chunkIndex} 上傳失敗: ${error.message}`);
        }
        await this.delay(1000 * attempt); // 指數(shù)退避
      }
    }
  }

  // 合并分片
  async mergeChunks(fileHash, fileName, totalChunks) {
    const response = await axios.post('/toolbox/video/merge-chunks', {
      fileHash,
      fileName,
      totalChunks
    });
    return response.data;
  }

  // 延遲函數(shù)
  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  // 執(zhí)行上傳
  async upload(file) {
    try {
      const fileHash = await this.generateFileHash(file);
      const fileSize = file.size;
      const totalChunks = Math.ceil(fileSize / this.chunkSize);
      
      // 檢查是否已上傳部分分片
      const uploadedChunks = await this.checkUploadedChunks(fileHash);
      
      const uploadPromises = [];
      let uploadedCount = uploadedChunks.length;

      // 更新進(jìn)度
      this.updateProgress(uploadedCount, totalChunks);

      for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
        // 跳過(guò)已上傳的分片
        if (uploadedChunks.includes(chunkIndex)) {
          continue;
        }

        const start = chunkIndex * this.chunkSize;
        const end = Math.min(fileSize, start + this.chunkSize);
        const chunk = file.slice(start, end);

        const uploadPromise = this.uploadChunk(
          fileHash, 
          chunk, 
          chunkIndex, 
          totalChunks, 
          file.name
        ).then(() => {
          uploadedCount++;
          this.updateProgress(uploadedCount, totalChunks);
        });

        uploadPromises.push(uploadPromise);

        // 控制并發(fā)數(shù)量
        if (uploadPromises.length >= this.concurrentUploads) {
          await Promise.race(uploadPromises);
          // 移除已完成的Promise
          uploadPromises.splice(uploadPromises.findIndex(p => p.isCompleted), 1);
        }
      }

      // 等待所有分片上傳完成
      await Promise.all(uploadPromises);

      // 合并分片
      const result = await this.mergeChunks(fileHash, file.name, totalChunks);
      
      this.onComplete(result);
      return result;

    } catch (error) {
      this.onError(error);
      throw error;
    }
  }

  updateProgress(uploaded, total) {
    const percent = Math.round((uploaded / total) * 100);
    this.onProgress(percent);
  }

  async checkUploadedChunks(fileHash) {
    try {
      const response = await axios.get(`/toolbox/video/uploaded-chunks?fileHash=${fileHash}`);
      return response.data.uploadedChunks || [];
    } catch (error) {
      return [];
    }
  }
}

// 使用示例
const uploader = new ChunkedUploader({
  chunkSize: 5 * 1024 * 1024, // 5MB
  concurrentUploads: 3,
  onProgress: (percent) => {
    console.log(`上傳進(jìn)度: ${percent}%`);
    // 更新UI進(jìn)度條
    document.getElementById('progress-bar').style.width = `${percent}%`;
  },
  onComplete: (result) => {
    console.log('上傳完成:', result);
    alert('文件上傳成功!');
  },
  onError: (error) => {
    console.error('上傳失敗:', error);
    alert('上傳失敗,請(qǐng)重試');
  }
});

// 開始上傳
document.getElementById('file-input').addEventListener('change', async (event) => {
  const file = event.target.files[0];
  if (file) {
    await uploader.upload(file);
  }
});

后端分片處理接口(Spring Boot示例):

@RestController
@RequestMapping("/toolbox/video")
public class ChunkedUploadController {
    
    @Value("${upload.temp.dir:/tmp/uploads}")
    private String uploadTempDir;
    
    // 分片上傳
    @PostMapping("/chunk-upload")
    public ResponseEntity<Map<String, Object>> uploadChunk(
            @RequestParam("chunk") MultipartFile chunk,
            @RequestParam("chunkIndex") Integer chunkIndex,
            @RequestParam("totalChunks") Integer totalChunks,
            @RequestParam("fileHash") String fileHash,
            @RequestParam("fileName") String fileName) {
        
        try {
            // 創(chuàng)建臨時(shí)目錄
            File tempDir = new File(uploadTempDir, fileHash);
            if (!tempDir.exists()) {
                tempDir.mkdirs();
            }
            
            // 保存分片文件
            File chunkFile = new File(tempDir, chunkIndex.toString());
            chunk.transferTo(chunkFile);
            
            // 記錄上傳的分片索引(可存入數(shù)據(jù)庫(kù)或Redis)
            this.recordUploadedChunk(fileHash, chunkIndex);
            
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("chunkIndex", chunkIndex);
            return ResponseEntity.ok(result);
            
        } catch (IOException e) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(result);
        }
    }
    
    // 合并分片
    @PostMapping("/merge-chunks")
    public ResponseEntity<Map<String, Object>> mergeChunks(
            @RequestBody MergeRequest request) {
        
        try {
            File tempDir = new File(uploadTempDir, request.getFileHash());
            File outputFile = new File(uploadTempDir, request.getFileName());
            
            try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                for (int i = 0; i < request.getTotalChunks(); i++) {
                    File chunkFile = new File(tempDir, String.valueOf(i));
                    try (FileInputStream fis = new FileInputStream(chunkFile)) {
                        byte[] buffer = new byte[8192];
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            fos.write(buffer, 0, bytesRead);
                        }
                    }
                    // 刪除分片文件
                    chunkFile.delete();
                }
            }
            
            // 刪除臨時(shí)目錄
            tempDir.delete();
            
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("filePath", outputFile.getAbsolutePath());
            return ResponseEntity.ok(result);
            
        } catch (IOException e) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(result);
        }
    }
    
    // 檢查已上傳的分片
    @GetMapping("/uploaded-chunks")
    public ResponseEntity<Map<String, Object>> getUploadedChunks(
            @RequestParam String fileHash) {
        
        // 從數(shù)據(jù)庫(kù)或Redis查詢已上傳的分片
        List<Integer> uploadedChunks = this.getRecordedChunks(fileHash);
        
        Map<String, Object> result = new HashMap<>();
        result.put("uploadedChunks", uploadedChunks);
        return ResponseEntity.ok(result);
    }
    
    private void recordUploadedChunk(String fileHash, Integer chunkIndex) {
        // 實(shí)現(xiàn)分片記錄邏輯,可存入Redis或數(shù)據(jù)庫(kù)
    }
    
    private List<Integer> getRecordedChunks(String fileHash) {
        // 實(shí)現(xiàn)獲取已上傳分片邏輯
        return new ArrayList<>();
    }
    
    public static class MergeRequest {
        private String fileHash;
        private String fileName;
        private Integer totalChunks;
        
        // getters and setters
    }
}

方案三:流式上傳與壓縮優(yōu)化

對(duì)于實(shí)時(shí)性要求高的場(chǎng)景,可以考慮流式上傳:

// 流式上傳實(shí)現(xiàn)
class StreamUploader {
  constructor(file, onProgress) {
    this.file = file;
    this.onProgress = onProgress;
    this.chunkSize = 64 * 1024; // 64KB
    this.currentOffset = 0;
  }

  async startUpload() {
    while (this.currentOffset < this.file.size) {
      const chunk = this.file.slice(
        this.currentOffset, 
        this.currentOffset + this.chunkSize
      );
      
      await this.uploadChunk(chunk);
      this.currentOffset += this.chunkSize;
      
      const progress = (this.currentOffset / this.file.size) * 100;
      this.onProgress(Math.min(progress, 100));
    }
  }

  async uploadChunk(chunk) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('offset', this.currentOffset);
    formData.append('totalSize', this.file.size);
    
    await axios.post('/stream-upload', formData);
  }
}

性能優(yōu)化與最佳實(shí)踐

1. 前端性能優(yōu)化

內(nèi)存管理:

// 及時(shí)釋放內(nèi)存
function processLargeFile(file) {
  return new Promise((resolve) => {
    const chunkSize = 1024 * 1024; // 1MB
    const chunks = [];
    let offset = 0;
    
    const readNextChunk = () => {
      const chunk = file.slice(offset, offset + chunkSize);
      const reader = new FileReader();
      
      reader.onload = (e) => {
        chunks.push(e.target.result);
        offset += chunkSize;
        
        if (offset < file.size) {
          // 使用setTimeout避免阻塞主線程
          setTimeout(readNextChunk, 0);
        } else {
          resolve(chunks);
        }
      };
      
      reader.readAsArrayBuffer(chunk);
    };
    
    readNextChunk();
  });
}

2. 用戶體驗(yàn)優(yōu)化

友好的進(jìn)度反饋:

// 完整的進(jìn)度管理組件
class UploadProgressManager {
  constructor() {
    this.uploadQueue = new Map();
  }
  
  addUpload(taskId, fileName) {
    this.uploadQueue.set(taskId, {
      fileName,
      progress: 0,
      status: 'pending',
      startTime: Date.now()
    });
    this.updateUI();
  }
  
  updateProgress(taskId, progress) {
    const task = this.uploadQueue.get(taskId);
    if (task) {
      task.progress = progress;
      task.status = progress === 100 ? 'completed' : 'uploading';
      this.updateUI();
    }
  }
  
  updateUI() {
    // 更新頁(yè)面上的進(jìn)度顯示
    const progressContainer = document.getElementById('upload-progress');
    progressContainer.innerHTML = '';
    
    this.uploadQueue.forEach((task, taskId) => {
      const taskElement = this.createTaskElement(taskId, task);
      progressContainer.appendChild(taskElement);
    });
  }
  
  createTaskElement(taskId, task) {
    const div = document.createElement('div');
    div.className = `upload-task ${task.status}`;
    div.innerHTML = `
      <div class="file-name">${task.fileName}</div>
      <div class="progress-bar">
        <div class="progress-fill" style="width: ${task.progress}%"></div>
      </div>
      <div class="status">${this.getStatusText(task)}</div>
    `;
    return div;
  }
  
  getStatusText(task) {
    switch (task.status) {
      case 'pending': return '等待上傳';
      case 'uploading': return `上傳中 ${task.progress}%`;
      case 'completed': return '上傳完成';
      default: return '未知狀態(tài)';
    }
  }
}

測(cè)試與監(jiān)控

自動(dòng)化測(cè)試

// 上傳功能測(cè)試套件
describe('大文件上傳測(cè)試', () => {
  test('分片上傳功能', async () => {
    // 創(chuàng)建模擬大文件
    const largeFile = new File(['x'.repeat(50 * 1024 * 1024)], 'test.mp4');
    
    const uploader = new ChunkedUploader({
      chunkSize: 5 * 1024 * 1024
    });
    
    const result = await uploader.upload(largeFile);
    expect(result.success).toBe(true);
  });
  
  test('網(wǎng)絡(luò)中斷恢復(fù)', async () => {
    // 模擬網(wǎng)絡(luò)中斷場(chǎng)景
    // 驗(yàn)證斷點(diǎn)續(xù)傳功能
  });
});

性能監(jiān)控

// 上傳性能監(jiān)控
class UploadMonitor {
  constructor() {
    this.metrics = [];
  }
  
  recordUpload(startTime, fileSize, success) {
    const duration = Date.now() - startTime;
    const speed = fileSize / (duration / 1000); // bytes per second
    
    this.metrics.push({
      timestamp: new Date(),
      fileSize,
      duration,
      speed,
      success
    });
    
    // 定期上報(bào)監(jiān)控?cái)?shù)據(jù)
    if (this.metrics.length >= 10) {
      this.reportMetrics();
    }
  }
  
  reportMetrics() {
    // 上報(bào)性能數(shù)據(jù)到監(jiān)控系統(tǒng)
    console.log('Upload metrics:', this.metrics);
    this.metrics = [];
  }
}

結(jié)論

大文件上傳失敗的問(wèn)題看似簡(jiǎn)單,實(shí)則涉及前端、后端、網(wǎng)絡(luò)、運(yùn)維等多個(gè)技術(shù)領(lǐng)域。通過(guò)本文的深度分析和完整解決方案,我們可以得出以下結(jié)論:

  • 問(wèn)題根源多樣:從服務(wù)器配置到網(wǎng)絡(luò)環(huán)境,都可能成為大文件上傳的瓶頸
  • 分片上傳是最佳實(shí)踐:它不僅解決了大文件上傳的問(wèn)題,還提供了更好的用戶體驗(yàn)
  • 監(jiān)控與測(cè)試不可或缺:只有通過(guò)完善的監(jiān)控和測(cè)試,才能確保上傳功能的穩(wěn)定性
  • 用戶體驗(yàn)至關(guān)重要:良好的進(jìn)度反饋和錯(cuò)誤處理能顯著提升用戶滿意度

在實(shí)際項(xiàng)目中,建議采用分片上傳作為基礎(chǔ)方案,結(jié)合適當(dāng)?shù)膲嚎s和流式處理技術(shù),同時(shí)建立完善的監(jiān)控體系。這樣不僅能解決當(dāng)前的大文件上傳問(wèn)題,還能為未來(lái)的擴(kuò)展打下堅(jiān)實(shí)基礎(chǔ)。

記住,技術(shù)解決方案的最終目標(biāo)是服務(wù)于業(yè)務(wù)需求和用戶體驗(yàn)。選擇適合自己項(xiàng)目階段的方案,平衡開發(fā)成本與用戶體驗(yàn),才是工程技術(shù)的最佳實(shí)踐。

到此這篇關(guān)于前端JS大文件上傳失敗問(wèn)題深度解析和完美解決方案的文章就介紹到這了,更多相關(guān)JS大文件上傳失敗解決內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解js中class的多種函數(shù)封裝方法

    詳解js中class的多種函數(shù)封裝方法

    這篇文章主要介紹了詳解js中class的多種函數(shù)封裝方法,介紹了不同函數(shù)的封裝方法,感興趣的朋友可以參考一下
    2016-01-01
  • webpack配置打包后圖片路徑出錯(cuò)的解決

    webpack配置打包后圖片路徑出錯(cuò)的解決

    本篇文章主要介紹了webpack配置打包后圖片路徑出錯(cuò)的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • Bootstrap 填充Json數(shù)據(jù)的實(shí)例代碼

    Bootstrap 填充Json數(shù)據(jù)的實(shí)例代碼

    本篇文章主要介紹了Bootstrap 填充Json數(shù)據(jù)的實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域

    JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域

    這篇文章主要為大家介紹了JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 前端在線預(yù)覽PDF文件三種實(shí)現(xiàn)方式(兼容移動(dòng)端)

    前端在線預(yù)覽PDF文件三種實(shí)現(xiàn)方式(兼容移動(dòng)端)

    這篇文章主要介紹了前端在線預(yù)覽PDF文件三種實(shí)現(xiàn)方式的相關(guān)資料,分別是使用微軟在線預(yù)覽地址、直接使用window.open打開文檔鏈接以及使用PDF.js,PDF.js方法穩(wěn)定,適用于大多數(shù)文件,每種方法都給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2025-02-02
  • JS根據(jù)變量保存方法名并執(zhí)行方法示例

    JS根據(jù)變量保存方法名并執(zhí)行方法示例

    用eval方法,把傳進(jìn)來(lái)的這個(gè)方法名所代表的方法當(dāng)作一個(gè)對(duì)象來(lái)賦值給method1的func屬性,需要的朋友可以參考下
    2014-04-04
  • 最新評(píng)論

    古蔺县| 呼玛县| 霍邱县| 桐梓县| 蒙自县| 河源市| 石阡县| 龙井市| 阿克陶县| 菏泽市| 巨鹿县| 额济纳旗| 汝州市| 浮山县| 江口县| 聂拉木县| 赫章县| 海伦市| 惠安县| 永新县| 晋宁县| 蒲城县| 岑巩县| 锦屏县| 博罗县| 德令哈市| 沛县| 南陵县| 虹口区| 安西县| 高台县| 玉门市| 宜昌市| 安国市| 紫金县| 体育| 合江县| 勃利县| 重庆市| 绥宁县| 香港 |