RxJS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд░реНрд╡рд░ рдкрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЗрдВрдЯрд░рдПрдХреНрдЯрд┐рд╡ рдЕрдкрд▓реЛрдб



RxJS рдХреА рдореВрд▓ рдмрд╛рддреЛрдВ рдкрд░ рдЕрдкрдирд╛ рдЖрдЦрд┐рд░реА рд▓реЗрдЦ рд▓рд┐рдЦрдиреЗ рдХреЗ рдмрд╛рдж рдореБрдЭреЗ рдПрдХ рд▓рдВрдмрд╛ рд╕рдордп рд╣реЛ рдЧрдпрд╛ рд╣реИред рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ, рдореБрдЭреЗ рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдЙрджрд╛рд╣рд░рдг рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЧрдпрд╛ рдЬреЛ рдЕрднреНрдпрд╛рд╕ рдореЗрдВ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдереНрдпреЛрд░реА рдХреЛ рдереЛрдбрд╝рд╛ рдкрддрд▓рд╛ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдФрд░ рдЖрдЬ рд╣рдо рдлрд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреА рдмрд╛рдд рдХрд░реЗрдВрдЧреЗред

рд╣рдо рдХреНрдпрд╛ рдХрд░реЗрдВ?

  • рд╣рдо рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдкреЗрдЬ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬрд╣рд╛рдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ
  • рдПрдХ рдкреНрд░рдЧрддрд┐ рдкрдЯреНрдЯреА рдЬреЛрдбрд╝реЗрдВ рддрд╛рдХрд┐ рдлрд╝рд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдкреНрд░рдЧрддрд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛред
  • рд░рджреНрдж рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдХреЗ рдбрд╛рдЙрдирд▓реЛрдб рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝реЗрдВ

рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдмреБрдирд┐рдпрд╛рджреА RxJS рдЬреНрдЮрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдХреНрдпрд╛ рд╣реИрдВ , рдСрдкрд░реЗрдЯрд░ , рд╕рд╛рде рд╣реА рд╕рд╛рде рдПрдЪрдУрдУ рдСрдкрд░реЗрдЯрд░ рднреА

рд╣рдо рдмрд┐рд▓реНрд▓реА рдХреЛ рдкреВрдВрдЫ рд╕реЗ рдирд╣реАрдВ рдЦреАрдВрдЪреЗрдВрдЧреЗ рдФрд░ рддреБрд░рдВрдд рд╡реНрдпрд╛рдкрд╛рд░ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЙрддрд░реЗрдВрдЧреЗ!

рдкреНрд░рд╢рд┐рдХреНрд╖рдг


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдПрдХ рд╕рд░реНрд╡рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдбрд╛рдЙрдирд▓реЛрдб рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░ рд╕рдХреЗред рдХреЛрдИ рднреА рд╕рд░реНрд╡рд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдореИрдВ рдЖрд░реНрдЯрд┐рдХрд▓ рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕рдкреНрд░реЗрд╕ рдФрд░ рдорд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рдиреЛрдб.рдЬреЗрдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ :

const express = require("express");
const multer  = require("multer");

const app = express();
const upload = multer({ dest:"files" });

app.post("/upload", upload.single("file"), function (req, res) {
    const { file } = req;

    if (file) {
        res.send("File uploaded successfully");
    } else {
        res.error("Error");
    }

});

app.listen(3000);

рдЕрдм рдПрдХ html рдкреЗрдЬ рдмрдирд╛рдПрдВ рдЬрд┐рд╕ рдкрд░ рд╣рдо рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рддрддреНрд╡ рд░рдЦреЗрдВрдЧреЗ:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>File uploading</title>
</head>
<body>
    <label for="file">load file: <input id="file" type="file"></label>
    <button id="upload">Upload</button>
    <button id="cancel">Cancel</button>
    <div id="progress-bar" style="width: 0; height: 2rem; background-color: aquamarine;"></div>
    <script src="index.js" type="text/javascript"></script>
</body>
</html>

рдЕрдм рдкреГрд╖реНрда рдкрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ 4 рддрддреНрд╡ рд╣реИрдВ рдЬрд┐рдирдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдмрд╛рддрдЪреАрдд рдХрд░реЗрдЧрд╛:

  • рдЯрд╛рдЗрдк рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЗрдирдкреБрдЯ рддрд╛рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░ рд╕рдХреЗ
  • рдЕрдкрд▓реЛрдб рдмрдЯрди, рдЬрдм рдХреНрд▓рд┐рдХ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдо рдЕрдкрд▓реЛрдб рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрдВрдЧреЗ
  • рд░рджреНрдж рдХрд░реЗрдВ рдмрдЯрди рдЬреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХреЛ рд░рджреНрдж рдХрд░ рджреЗрдЧрд╛
  • 0. рдХреА рд╢реБрд░реБрдЖрддреА рдЪреМрдбрд╝рд╛рдИ рдХреЗ рд╕рд╛рде рдкреНрд░рдЧрддрд┐ рдкрдЯреНрдЯреАред рдЕрдкрд▓реЛрдб рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рджреМрд░рд╛рди, рд╣рдо рдЗрд╕рдХреА рдЪреМрдбрд╝рд╛рдИ рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗ

рдмреЙрдбреА рдЯреИрдЧ рдХреЗ рдЕрдВрдд рдореЗрдВ, рдореИрдВрдиреЗ index.js рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдЬреЛрдбрд╝рд╛, рдЬрд┐рд╕реЗ рд╣рдореЗрдВ рднреА рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛:

//   ,     
const input = document.querySelector('#file');
const uploadBtn = document.querySelector('#upload');
const progressBar = document.querySelector('#progress-bar');
const cancelBtn = document.querySelector('#cancel');

рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:



рд╕рдм рдХреБрдЫ рдПрдХ рдкреНрд░рд╡рд╛рд╣ рд╣реИ


рдпрд╣ рдмрддрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреМрди рд╕реА рдлрд╛рдЗрд▓ рдХреЛ рдЪреБрдирдирд╛ рд╣реИ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ "рдлрд╛рдЗрд▓ рдЪреБрдиреЗрдВ" рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЙрд╕рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХрд╛ рд╕рдВрд╡рд╛рдж рдмреЙрдХреНрд╕ рдЦреБрд▓ рдЬрд╛рдПрдЧрд╛, рдЬрд╣рд╛рдВ рдлрд╝реЛрд▓реНрдбрд░ рдЯреНрд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдЧрд╛ред

рд╣рдо рдХреИрд╕реЗ рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рд╣реИ? рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ "рдкрд░рд┐рд╡рд░реНрддрди" рдШрдЯрдирд╛ рд╣реИред рдШрдЯрдирд╛ рдХреЗ рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдЗрдирдкреБрдЯ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕рд░рдгреА рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдБ рдлрд╝рд╛рдЗрд▓ рдбреЗрдЯрд╛ рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред

рд╣рдо рдкрд░рд┐рд╡рд░реНрддрди рдХреА рдШрдЯрдирд╛ рдХреЛ рдХреИрд╕реЗ рд╕реБрдирддреЗ рд╣реИрдВ? рдЖрдк addEventListener рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╣рдо RxJS рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рдХрд┐рд╕реА рднреА рдШрдЯрдирд╛ рдХреЛ рдПрдХ рдзрд╛рд░рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рджрд░реНрд╢рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

fromEvent(input, 'change').pipe(
    //    
    map(() => input.files[0])
).subscribe({
    next: data => console.log(file)
});

рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рдЬреЛрдбрд╝реЗрдВ, рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдкрд▓реЛрдб рдХрд░реЗрдЧрд╛ред рдЕрднреА рдХреЗ рд▓рд┐рдП, рдЙрд╕рдХреЗ рд╢рд░реАрд░ рдХреЛ рдЦрд╛рд▓реА рдЫреЛрдбрд╝ рджреЗрдВ:

function upload(file) {
  console.log(file);
}

рдЕрдкрд▓реЛрдб рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:

fromEvent(uploadBtn, 'click').subscribe({
  next: () => upload(input.files[0])
});

рдзрд╛рд░рд╛рдУрдВ рдХреЛ рдорд┐рд▓рд╛рдПрдВ


рдЕрдм рд╣рдорд╛рд░рд╛ рдХреЛрдб addEventListener рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рдо рдЬреЛ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЙрд╕рд╕реЗ рдЕрд▓рдЧ рдирд╣реАрдВ рд╣реИред рд╣рд╛рдВ, рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо рдЗрд╕реЗ рдРрд╕реЗ рд╣реА рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдЙрди рд▓рд╛рднреЛрдВ рдХреЛ рдЦреЛ рджреЗрдВрдЧреЗ рдЬреЛ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рд╣рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

рд╣рдо рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ? рд╣рдо рдлрд╝рд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рдЪрд░рдгреЛрдВ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВрдЧреЗ:

  • рдлрд╝рд╛рдЗрд▓ рдЪрдпрди
  • рдЕрдкрд▓реЛрдб рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ
  • Input.files рд╕реЗ рдлрд╝рд╛рдЗрд▓ рдирд┐рдХрд╛рд▓реЗрдВ
  • рдлрд╛рдЗрд▓ рдЕрдкрд▓реЛрдб

рдЕрдм рд╣рдо рдЗрд╕ рдЕрдиреБрдХреНрд░рдо рдХреЛ рдХреЛрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЗрдирдкреБрдЯ рдФрд░ рдЕрдкрд▓реЛрдб рдХреЛ рдХреИрд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдП? рд╕реНрд╡рд┐рдЪрдкрд╛рдЗрдк рдСрдкрд░реЗрдЯрд░ рд╣рдореЗрдВ рдЗрд╕рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛, рдЬреЛ рд╣рдореЗрдВ рдПрдХ рдзрд╛рдЧреЗ рдХреЛ рджреВрд╕рд░реЗ рдкрд░ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ:

fromEvent(input, 'change').pipe(
    switchMap(() => fromEvent(uploadBtn, 'click')),
    map(() => input.files[0])
).subscribe({
    next: file => upload(file)
});

рдпрд╣ рдХреЛрдб рдЙрди рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдХреЗ рд╕рдорд╛рди рд╣реИ рдЬреЛ рд╣рдордиреЗ рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдП рд╣реИрдВред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ, рд╕реНрд╡рд┐рдЪрдкрд╛рдЗрдк рдЯреНрд░рд┐рдЧрд░ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рд╣рдо рдЕрдкрд▓реЛрдбрдмрдЯрди рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рддрдм рдХреБрдЫ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред

рд╕реНрд╡рд┐рдЪрдкрд╛рдЗрдВрдЯ рдХреЗрд╡рд▓ рдмрд╛рд╣рд░реА рдореВрд▓реНрдпреЛрдВ (рдЕрдкрд▓реЛрдбрдмрдЯрди, 'рдХреНрд▓рд┐рдХ') рд╕реЗ рдЙрддреНрдкрдиреНрди рдореВрд▓реНрдпреЛрдВ рдХреЛ рдмрд╛рд╣рд░реА рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ ред рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЕрдкрд▓реЛрдб рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рджреВрд╕рд░реЗ рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддреН рдЕрдкрд▓реЛрдбрдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВред рдлрд┐рд░ рдпрд╣ рдореИрдк рд╡рд┐рдзрд┐ рдХреЛ рдХрд╛рдо рдХрд░реЗрдЧрд╛, рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рд░рдгреА рд╕реЗ рдирд┐рдХрд╛рд▓реЗрдЧрд╛, рдФрд░ рдЕрдкрд▓реЛрдб рд╡рд┐рдзрд┐ рдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рджрд╕реНрдпрддрд╛ рдореЗрдВ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдпрд╣рд╛рдВ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдХреНрд░рдо рдЯреВрдЯрд╛ рдирд╣реАрдВ рд╣реИред рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП, 'рдкрд░рд┐рд╡рд░реНрддрди' рдШрдЯрдирд╛ рд╕реЗ рдкрд╣рд▓реЗ рдЖрдЧ рд▓рдЧрдиреА рдЪрд╛рд╣рд┐рдПред

рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА, рдПрдХ рд╕рдорд╕реНрдпрд╛ рдмрдиреА рд░рд╣реАред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рдЙрд╕рдХрд╛ рдЪрдпрди рд░рджреНрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдлрд┐рд░ рдЬрдм рд╣рдо рдлрд╝рд╛рдЗрд▓ рдХреЛ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдкрд╛рд╕ рд╣реЛрддреЗ рд╣реИрдВ - рдЕрдкрд░рд┐рднрд╛рд╖рд┐рддред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдЪреЗрдХ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рд┐рдП:

fromEvent(input, 'change').pipe(
    switchMap(() => fromEvent(uploadBtn, 'click')),
    map(() => input.files[0]),
    filter(file => !!file)
).subscribe({
    next: file => upload(file)
});

Xhr рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛


рдпрд╣ рд╕рдмрд╕реЗ рдХрдард┐рди - рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдореИрдВ рдЗрд╕реЗ xhr рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрд░ рджрд┐рдЦрд╛рдКрдВрдЧрд╛, рдЪреВрдВрдХрд┐ рд▓реЗрдЦрди рдХреЗ рд╕рдордп, рдпрд╣ рдкрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЕрдкрд▓реЛрдб рдкреНрд░рдЧрддрд┐ рдХреЛ рдХреИрд╕реЗ рдЯреНрд░реИрдХ рдХрд┐рдпрд╛ рдЬрд╛рдП ред
рдЖрдк рдХрд┐рд╕реА рдЕрдиреНрдп рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрддрд░рд╛рдИ рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП axios рдпрд╛ jQuery.ajaxред


рдЪреВрдБрдХрд┐ рдореИрдВ рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб рдкрд░ multer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдореБрдЭреЗ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдлреЙрд░реНрдо рдХреЗ рдЕрдВрджрд░ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ (multer рдХреЗрд╡рд▓ рдЗрд╕ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ)ред рдЗрд╕рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ createFormData рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрд╛ рд╣реИ:

function createFormData(file) {
    const form = new FormData();
    //       file
    form.append('file', file);
    return form;
}

fromEvent(input, 'change').pipe(
    switchMap(() => fromEvent(uploadBtn, 'click')),
    map(() => input.files[0]),
    filter(file => !!file),
    map(file => createFormData(file))
).subscribe({
    next: data => upload(data)
});

рд╣рдо XMLHttpRequest рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдлрд╝реЙрд░реНрдо рдХреЛ рдЕрдирд▓реЛрдб рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рдЗрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдиреЗ рдФрд░ рдЙрд╕ рдкрд░ рдЕрдирд▓реЛрдб рдФрд░ рдСрдирд░реЛрд░ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЕрдкрд▓реЛрдб рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░ рдкрд╣рд▓рд╛ рдлрд╛рдпрд░ рдХрд░реЗрдЧрд╛, рджреВрд╕рд░рд╛ рдЬрдм рддреНрд░реБрдЯрд┐ рд╣реЛрдЧреАред

function upload(data) {
    const xhr = new XMLHttpRequest();

    //        
    xhr.onload = () => console.log('success');

    //    
    xhr.onerror = e => console.error(e);

    //  
    xhr.open('POST', '/upload', true);

    //  
    xhr.send(data);
}

рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рд╣реИред рд▓реЗрдХрд┐рди рдЗрд╕рдореЗрдВ рдХреБрдЫ рдиреБрдХрд╕рд╛рди рднреА рд╣реИрдВ:

  • рдбрд╛рдЙрдирд▓реЛрдб рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ
  • рдЕрдЧрд░ рдЖрдк рдЕрдкрд▓реЛрдбрдмрдЯрди рдмрдЯрди рдкрд░ n рдмрд╛рд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдлрд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП n рд╕рдорд╛рдирд╛рдВрддрд░ рдХрдиреЗрдХреНрд╢рди рд╣реЛрдВрдЧреЗ

рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рд╕реНрдЯреНрд░реАрдо рд╕реЗ рдмрд╛рд╣рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд╡рд╣ рдЕрдкрдиреА рдорд░реНрдЬреА рд╕реЗ рд░рд╣рддреА рд╣реИред рд╣рдореЗрдВ рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред рдЪрд▓рд┐рдП рд╕рдорд╛рд░реЛрд╣ рдХреЛ рд╣рдо рддрдХ рд╡рд╛рдкрд╕ рдкрд╣реБрдВрдЪрд╛рддреЗ рд╣реИрдВред рддрдм рд╣рдо рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдЕрдкрд▓реЛрдб рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

function upload(data) {
    return new Observable(observer => {
        const xhr = new XMLHttpRequest();

        //    ,      
        //   
        xhr.onload = () => {
            observer.next();
            observer.complete();
        };
        
        xhr.onerror = e => observer.error(e);
        
        xhr.open('POST', '/upload', true);
        xhr.send(data);

        //   -  
        return () => xhr.abort();
    });
}

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЕрд╡рд▓реЛрдХрди рд╕рдорд╛рд░реЛрд╣ рдХреЗ рдЕрдВрджрд░ рд╡рд╛рдкрд╕ рдЖ рдЧрдпрд╛ рд╣реИред рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рд╕рджрд╕реНрдпрддрд╛ рд░рджреНрдж рдХрд░рдиреЗ рдФрд░ рдЕрдкрд▓реЛрдб рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХреЗ рд╕рдордп рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред

рдЕрдкрд▓реЛрдб рдХреЙрд▓ рдХреЛ switchMap рдореЗрдВ рд░рдЦреЗрдВ:

fromEvent(input, 'change').pipe(
    switchMap(() => fromEvent(uploadBtn, 'click')),
    map(() => input.files[0]),
    filter(file => !!file),
    map(file => createFormData(file)),
    switchMap(data => upload(data))
).subscribe({
    next: () => console.log('File uploaded')
});

рдЕрдм, рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкрд▓реЛрдб рдмрдЯрди рдкрд░ рдлрд┐рд░ рд╕реЗ рдХреНрд▓рд┐рдХ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдкрд┐рдЫрд▓рд╛ рдЕрдиреБрд░реЛрдз рд░рджреНрдж рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдПрдХ рдирдпрд╛ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдПрдХ рдХреНрд▓рд┐рдХ рдЕрдиреБрд░реЛрдз рд░рджреНрдж рдХрд░реЗрдВ


рдЕрднреА рднреА рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреИрд▓реНрд╕реЗрд▓рдмрдЯрди рдмрдЯрди рд╣реИред рд╣рдореЗрдВ рдЕрдиреБрд░реЛрдз рд░рджреНрдж рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЯреЗрдХрдСрдирдЯрд┐рд▓ рдСрдкрд░реЗрдЯрд░ рдпрд╣рд╛рдВ рдорджрдж рдХрд░реЗрдЧрд╛ред

takeUntil рдХрд╛ рдЕрдиреБрд╡рд╛рдж "рдмрд╛рдп рдмрд╛рдп" рд╣реЛрддрд╛ рд╣реИред рдпрд╣ рдСрдкрд░реЗрдЯрд░ рдмрд╛рд╣рд░реА рдзрд╛рд░рд╛ рд╕реЗ рдорд╛рди рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЖрдЧреЗ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдореЗрдВ рдиреАрдЪреЗ рджреЗрддрд╛ рд╣реИред рдЬрдм рддрдХ рдЖрдВрддрд░рд┐рдХ рдзрд╛рдЧрд╛ рдореМрдЬреВрдж рд╣реИ рдФрд░ рдХреБрдЫ рдирд╣реАрдВ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИред рдЬреИрд╕реЗ рд╣реА рдЖрдВрддрд░рд┐рдХ рдереНрд░реЗрдб рдПрдХ рдорд╛рди рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ, рдЯреЗрдХ рдпреВрдЯрд┐рд▓ рдЕрдирд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдФрд░ рдмрд╛рд╣рд░реА рдереНрд░реЗрдб рд╕реЗ рдЕрдирд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм рдХрд░реЗрдЧрд╛ред

рдСрдкрд░реЗрдЯрд░ рдЬреЛрдбрд╝рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХрд┐рд╕ рд╕реНрдЯреНрд░реАрдо рд╕реЗ рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо рдЕрдкрд▓реЛрдб рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рдлрд╝рд╛рдЗрд▓ рдХреЗ рдЕрдкрд▓реЛрдб рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЕрд░реНрдерд╛рддреНред рдЖрдВрддрд░рд┐рдХ рдзрд╛рдЧреЗ рд╕реЗ рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░реЗрдВ:

fromEvent(input, 'change').pipe(
    switchMap(() => fromEvent(uploadBtn, 'click')),
    map(() => input.files[0]),
    filter(file => !!file),
    map(file => createFormData(file)),
    switchMap(data => upload(data).pipe(
        //    upload
        takeUntil(fromEvent(cancelBtn, 'click'))
    ))
).subscribe({
    next: () => console.log('File uploaded')
});

рдкреНрд░рдЧрддрд┐ рдкрдЯреНрдЯреА


рдпрд╣ рдкреНрд░рдЧрддрд┐ рдкрдЯреНрдЯреА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдкреНрд░рдЧрддрд┐ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ xhr.upload.onprogress рдкрджреНрдзрддрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдкреНрд░реЛрдЧреНрд░реЗрд╕рд┐рд╡ рдЗрд╡реЗрдВрдЯ рд╣реЛрдиреЗ рдкрд░ рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдИрд╡реЗрдВрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдХрдИ рдЧреБрдг рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрддреЗ рд╣реИрдВ:

  • lengthComputable - рдпрджрд┐ рд╕рд╣реА рд╣реИ, рддреЛ рд╣рдо рдкреВрд░реНрдг рдлрд╝рд╛рдЗрд▓ рдЖрдХрд╛рд░ рдЬрд╛рдирддреЗ рд╣реИрдВ (рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрд╢рд╛ рд╕рдЪ)
  • рдХреБрд▓ - рдмрд╛рдЗрдЯреНрд╕ рдХреА рдХреБрд▓ рд╕рдВрдЦреНрдпрд╛
  • рднрд░реА рд╣реБрдИ - рднреЗрдЬреА рдЧрдИ рдмрд╛рдЗрдЯ рдХреА рд╕рдВрдЦреНрдпрд╛

рдЕрдкрд▓реЛрдб рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВ:

function upload(data) {
    return new Observable(observer => {
        const xhr = new XMLHttpRequest();

        xhr.upload.onprogress = e => {
            //  
            const progress = e.loaded / e.total * 100;
            observer.next(progress);
        };

        xhr.onerror = e => observer.error(e);
        xhr.onload = () => observer.complete();

        xhr.open('POST', '/upload', true);
        xhr.send(data);

        return () => xhr.abort();
    });
}

рдЕрдм рдЕрдкрд▓реЛрдб рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдЕрдкрд▓реЛрдб рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕реНрдкрд┐рдЯ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд░рд╣рддрд╛ рд╣реИ рдЬреЛ рдкреНрд░рдЧрддрд┐ рдХреЗ рд╢реИрд▓реА рдЧреБрдгреЛрдВ рдХреЛ рдмрджрд▓ рджреЗрдЧрд╛ред

function setProgressBarWidth(width) {
    progressBar.style.width = `${width}%`;
}

fromEvent(input, 'change').pipe(
   /* ..
   
   */
).subscribe({
    next: width => setProgressBarWidth(width)
});


рдПрдХ рддреНрд╡рд░рд┐рдд рдЯрд┐рдк: рддрд╛рдХрд┐ рдЖрдкрдХреА рдлрд╝рд╛рдЗрд▓реЗрдВ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдЗрддрдиреА рддреЗрдЬрд╝реА рд╕реЗ рдЕрдкрд▓реЛрдб рди рд╣реЛрдВ, Chrome devtools рдореЗрдВ "рдкреНрд░рджрд░реНрд╢рди" рдЯреИрдм рдореЗрдВ "рдлрд╛рд╕реНрдЯ 3G" рдпрд╛ "рдзреАрдореА 3G" рд╕реЗрдЯрд┐рдВрдЧ рдЪрд╛рд▓реВ рдХрд░реЗрдВред

рджрд┐рдорд╛рдЧ рдореЗрдВ рд▓рд╛рдУ


рд╣рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдЖрд╡реЗрджрди рдорд┐рд▓рд╛ред рдпрд╣ рд╕реНрдЯреНрд░реЛрдХ рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдЕрдм, рдЬрдм рдЖрдк рдЕрдкрд▓реЛрдб рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдкрд┐рдЫрд▓реЗ рдЕрдкрд▓реЛрдб рдХреЛ рд░рджреНрдж рдХрд░ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рдирдИ рд╢реБрд░реБрдЖрдд рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд░рджреНрдж рдмрдЯрди рд╣реИред

рдореИрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЕрдкрд▓реЛрдбрдмрдЯрди рдмрдЯрди рдмрд╛рдж рдХреЗ рдХреНрд▓рд┐рдХреЛрдВ рдХрд╛ рдЬрд╡рд╛рдм рди рджреЗ рдЬрдм рддрдХ рд╣рдо рдлрд╝рд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдирд╣реАрдВ рдХрд░рддреЗ (рдпрд╛ рдЬрдм рддрдХ рд╣рдо рдЕрдкрд▓реЛрдб рд░рджреНрдж рдирд╣реАрдВ рдХрд░рддреЗ)ред рдХреНрдпрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?

рдЕрдкрд▓реЛрдб рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреВрд░реА рд╣реЛрдиреЗ рддрдХ рдЖрдк рдбрд┐рд╕реЗрдмрд▓ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рд▓рдЯрдХрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдПрдХ рдФрд░ рд╡рд┐рдХрд▓реНрдк рд╣реИ - рдПрдЧреНрдЬреЙрд╕реНрдЯ рдореИрдк рдСрдкрд░реЗрдЯрд░ред рдпрд╣ рдХрдерди рдмрд╛рд╣рд░реА рдзрд╛рдЧреЗ рд╕реЗ рдирдП рдореВрд▓реНрдпреЛрдВ рдХреА рдЕрдирджреЗрдЦреА рдХрд░реЗрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдЖрдВрддрд░рд┐рдХ рдзрд╛рдЧрд╛ рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддрд╛ред рдПрдЧреНрдЬреЙрд╕реНрдЯ рд╕реНрд╡рд┐рдЪрдмрд╛рдЙрдЯ рдХреЛ рдердХрд╛рд╡рдЯ рдХреЗ рд╕рд╛рде рдмрджрд▓реЗрдВ:

exhaustMap(data => upload(data).pipe(
  takeUntil(fromEvent(cancelBtn, 'click'))
))

рдФрд░ рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдереЛрдбрд╝рд╛ рд░реАрдлреИрдХреНрдЯрд░рд┐рдВрдЧ рдФрд░ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ:

import { fromEvent, Observable } from "rxjs";
import { map, switchMap, filter, takeUntil, exhaustMap } from "rxjs/operators";

const input = document.querySelector('#file');
const uploadBtn = document.querySelector('#upload');
const progressBar = document.querySelector('#progress-bar');
const cancelBtn = document.querySelector('#cancel');

const fromUploadBtn = fromEvent(uploadBtn, 'click');
const fromCancelBtn = fromEvent(cancelBtn, 'click');

fromEvent(input, 'change').pipe(
    switchMap(() => fromUploadBtn),
    map(() => input.files[0]),
    filter(file => !!file),
    map(file => createFormData(file)),
    exhaustMap(data => upload(data).pipe(
        takeUntil(fromCancelBtn)
    ))
).subscribe({
    next: width => setProgressBarWidth(width)
});

function setProgressBarWidth(width) {
    progressBar.style.width = `${width}%`;
}

function createFormData(file) {
    const form = new FormData();
    form.append('file', file);
    return form;
}

function upload(data) {
    return new Observable(observer => {
        const xhr = new XMLHttpRequest();

        xhr.upload.onprogress = e => {
            const progress = e.loaded / e.total * 100;
            observer.next(progress);
        };

        xhr.onerror = e => observer.error(e);
        xhr.onload = () => observer.complete();

        xhr.open('POST', '/upload', true);
        xhr.send(data);

        return () => xhr.abort();
    });
}

рдореИрдВрдиреЗ рдЕрдкрдирд╛ рд╕рдВрд╕реНрдХрд░рдг рдпрд╣рд╛рдВ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рд╣реИ ред

рдХреЛрдгреАрдп рдФрд░ HttpClient


рдпрджрд┐ рдЖрдк рдХреЛрдгреАрдп рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд╕реАрдзреЗ xhr рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдХреЛрдгреАрдп рдХреА рдПрдХ HttpClient рд╕реЗрд╡рд╛ рд╣реИред рдпрд╣ рд╕реЗрд╡рд╛ рд▓реЛрдбрд┐рдВрдЧ / рдЕрдирд▓реЛрдбрд┐рдВрдЧ рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдЯреНрд░реИрдХ рдХрд░ рд╕рдХрддреА рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдирд┐рдореНрди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкреЛрд╕реНрдЯ рд╡рд┐рдзрд┐ рдореЗрдВ рдкрд╛рд╕ рдХрд░рдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ:

  • reportProgress: true - рдЕрдкрд▓реЛрдб / рдбрд╛рдЙрдирд▓реЛрдб рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
  • рдЕрд╡рд▓реЛрдХрди рдХрд░реЗрдВ: "рдШрдЯрдирд╛рдПрдБ" - рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВ рдХрд┐ рд╣рдо рд╕реНрдЯреНрд░реАрдо рд╕реЗ HttpEvents рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ

рдпрд╣рд╛рдВ рджреЗрдЦреЗрдВ рдХрд┐ рдХреЛрдгреАрдп рдореЗрдВ рдЕрдкрд▓реЛрдб рд╡рд┐рдзрд┐ рдХреНрдпрд╛ рд╣реЛрдЧреА:

export class UploaderService {
  constructor(private http: HttpClient) { }

  public upload(data: FormData): Observable<number> {
    return this.http.post('/upload', data, { reportProgress: true, observe: 'events' })
      .pipe(
        filter(event => event.type === HttpEventType.UploadProgress),
        map(event => event as HttpProgressEvent),
        map(event => event.loaded / event.total * 100)
      );
  }
}

рдлрд╝рд┐рд▓реНрдЯрд░ рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рдХреЗрд╡рд▓ рдЕрдкрд▓реЛрдб рдХреА рдЧрдИ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рддрд╛ рд╣реИред рдЕрдиреНрдп рдШрдЯрдирд╛рдПрдБ рд╣рдореЗрдВ рд░реБрдЪрддреА рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рд╣рдо рд▓реЛрдб рдФрд░ рдХреБрд▓ рд╕рдВрдкрддреНрддрд┐рдпреЛрдВ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╡реЗрдВрдЯ рдХреЛ HttpProgressEvent рдореЗрдВ рд▓рд╛рддреЗ рд╣реИрдВред рд╣рдо рдкреНрд░рддрд┐рд╢рдд рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред

HttpClient xhr рдкрд░ рд╕рд┐рд░реНрдл рдПрдХ рдЖрд╡рд░рдг рд╣реИ рдЬреЛ рд╣рдореЗрдВ рдПрдХ рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИ рдФрд░ HTTP рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИред

рдХреЛрдгреАрдп рдкрд░ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдЖрд╡реЗрджрди рдпрд╣рд╛рдБ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред

рдирд┐рд╖реНрдХрд░реНрд╖


RxJS рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд╣рд╛рдереЛрдВ рдореЗрдВ рдПрдХ рдмрд╣реБрдд рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЙрдкрдХрд░рдг рд╣реИред рдЙрдирдХреЗ рд╢рд╕реНрддреНрд░рд╛рдЧрд╛рд░ рдореЗрдВ рд╕рднреА рдЕрд╡рд╕рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдСрдкрд░реЗрдЯрд░реЛрдВ рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рд╕рдореВрд╣ рд╣реИред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдЗрд╕ рд╡рдЬрд╣ рд╕реЗ, рдЗрд╕ рддрдХрдиреАрдХ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреА рджрд╣рд▓реАрдЬ рдХрд╛рдлреА рдЕрдзрд┐рдХ рд╣реИред рдФрд░ рдЕрдХреНрд╕рд░, рд▓реЛрдЧ рдЕрдирдЬрд╛рдиреЗ рдореЗрдВ рдЕрдкрдиреА "рдмрд╛рдЗрдХ" рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдХреЛрдб рдХреЛ рдмрдирд╛рдП рд░рдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред

рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ рд╕рднреА рдкрд╛рдардХ рдЕрднреА рднреА рдЦрдбрд╝реЗ рди рд╣реЛрдВ рдФрд░ рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рди рдбрд░реЗрдВред RxJS рд╕реАрдЦреЗрдВред рдЕрдЪрд╛рдирдХ, рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдСрдкрд░реЗрдЯрд░ рдЖрддрд╛ рд╣реИ рдЬреЛ рдХреЛрдб рдХреА 10 рд▓рд╛рдЗрдиреЛрдВ рдХреЛ рдПрдХ рдореЗрдВ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИред рдпрд╛ рдпрд╣ рдХреЛрдб рдХреЛ рдереЛрдбрд╝рд╛ рд╕реНрдкрд╖реНрдЯ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред

рд╕реМрднрд╛рдЧреНрдп

Source: https://habr.com/ru/post/undefined/


All Articles