{"id":298482,"date":"2020-02-10T21:00:12","date_gmt":"2020-02-10T21:00:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=298482"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=298482","title":{"rendered":"\u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0RxJS"},"content":{"rendered":"\n<div class=\"post__text post__text-html\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/487836\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oo\/ei\/f7\/ooeif7l8-qpd0wfxxriskilepha.png\"><\/p>\n<p>  \u041f\u0440\u043e\u0448\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440, \u043a\u0430\u043a \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c RxJS. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043c\u0435\u043d\u044f \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0444\u0430\u0439\u043b\u043e\u0432.<a name=\"habracut\"><\/a><\/p>\n<p>  \u0427\u0442\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c?<\/p>\n<ul>\n<li>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0435\u0433\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u0438\u043c progress bar, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b\u0430<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430\u0436\u0430\u0442\u0438\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u043e\u0442\u043c\u0435\u043d\u044b<\/li>\n<\/ul>\n<p>  <\/p>\n<blockquote><p>\u0414\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f RxJS. \u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 <a href=\"https:\/\/habr.com\/ru\/post\/438642\/\">Observable<\/a>, <a href=\"https:\/\/habr.com\/ru\/post\/444290\/\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b<\/a>, \u0430 \u0442\u0430\u043a-\u0436\u0435 <a href=\"https:\/\/habr.com\/ru\/post\/450050\/\">HOO \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b<\/a><\/p><\/blockquote>\n<p>  \u041d\u0435 \u0431\u0443\u0434\u0435\u043c \u0442\u044f\u043d\u0443\u0442\u044c \u043a\u043e\u0442\u0430 \u0437\u0430 \u0445\u0432\u043e\u0441\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0434\u0435\u043b\u0443!<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h2>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0444\u0430\u0439\u043b\u043e\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u043e\u0439\u0442\u0438 \u043b\u044e\u0431\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u044f \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c node.js \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 express \u0438 <a href=\"https:\/\/github.com\/expressjs\/multer\">multer<\/a>:<\/p>\n<pre><code class=\"javascript\">const express = require(&quot;express&quot;); const multer  = require(&quot;multer&quot;);  const app = express(); const upload = multer({ dest:&quot;files&quot; });  app.post(&quot;\/upload&quot;, upload.single(&quot;file&quot;), function (req, res) {     const { file } = req;      if (file) {         res.send(&quot;File uploaded successfully&quot;);     } else {         res.error(&quot;Error&quot;);     }  });  app.listen(3000); <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c html \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:<\/p>\n<pre><code class=\"xml\">&lt;!doctype html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt;     &lt;meta charset=&quot;UTF-8&quot;&gt;     &lt;meta name=&quot;viewport&quot;           content=&quot;width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0&quot;&gt;     &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt;     &lt;title&gt;File uploading&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt;     &lt;label for=&quot;file&quot;&gt;load file: &lt;input id=&quot;file&quot; type=&quot;file&quot;&gt;&lt;\/label&gt;     &lt;button id=&quot;upload&quot;&gt;Upload&lt;\/button&gt;     &lt;button id=&quot;cancel&quot;&gt;Cancel&lt;\/button&gt;     &lt;div id=&quot;progress-bar&quot; style=&quot;width: 0; height: 2rem; background-color: aquamarine;&quot;&gt;&lt;\/div&gt;     &lt;script src=&quot;index.js&quot; type=&quot;text\/javascript&quot;&gt;&lt;\/script&gt; &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c 4 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c:<\/p>\n<ul>\n<li>Input \u0441 \u0442\u0438\u043f\u043e\u043c file, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043c\u043e\u0433 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438<\/li>\n<li>\u041a\u043d\u043e\u043f\u043a\u0430 upload, \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443<\/li>\n<li>\u041a\u043d\u043e\u043f\u043a\u0430 cancel, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443<\/li>\n<li>Progress bar \u0441\u043e \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u0448\u0438\u0440\u0438\u043d\u043e\u0439 0. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0448\u0438\u0440\u0438\u043d\u0443<\/li>\n<\/ul>\n<p>  \u0412 \u0441\u0430\u043c\u043e\u043c \u043a\u043e\u043d\u0446\u0435 \u0442\u0435\u0433\u0430 body \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u043a\u0440\u0438\u043f\u0442 index.js, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c:<\/p>\n<pre><code class=\"javascript\">\/\/ \u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c const input = document.querySelector('#file'); const uploadBtn = document.querySelector('#upload'); const progressBar = document.querySelector('#progress-bar'); const cancelBtn = document.querySelector('#cancel'); <\/code><\/pre>\n<p>  \u0412\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/vj\/aw\/wo\/vjawwosfr54pppzvsavg06mwmty.png\"><\/p>\n<h2>\u0412\u0441\u0451 \u2014 \u043f\u043e\u0442\u043e\u043a<\/h2>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0443, \u043a\u0430\u043a\u043e\u0439 \u0444\u0430\u0439\u043b \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 \u00abChoose file\u00bb. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u0432\u0430\u0448\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0433\u0434\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0441\u044f \u0434\u0435\u0440\u0435\u0432\u043e \u043f\u0430\u043f\u043e\u043a. \u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0444\u0430\u0439\u043b\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442 \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u043c.<\/p>\n<p>  \u041a\u0430\u043a \u043d\u0430\u043c \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0431\u0440\u0430\u043b \u0444\u0430\u0439\u043b? \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u00abchange\u00bb. \u041f\u043e\u0441\u043b\u0435 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u043c\u0430\u0441\u0441\u0438\u0432\u0443 files \u0432 input\u2019\u0435, \u043a\u0443\u0434\u0430 \u0438 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>  \u041a\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u00abchange\u00bb? \u041c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c addEventListener \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0438\u043c. \u041d\u043e \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 RxJS, \u0433\u0434\u0435 \u043b\u044e\u0431\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043a\u0430\u043a \u043f\u043e\u0442\u043e\u043a:<\/p>\n<pre><code class=\"javascript\">fromEvent(input, 'change').pipe(     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430     map(() =&gt; input.files[0]) ).subscribe({     next: data =&gt; console.log(file) }); <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e upload, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440. \u041f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0435\u0435 \u0442\u0435\u043b\u043e \u043f\u0443\u0441\u0442\u044b\u043c:<\/p>\n<pre><code class=\"javascript\">function upload(file) {   console.log(file); } <\/code><\/pre>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f upload \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 uploadBtn:<\/p>\n<pre><code class=\"javascript\">fromEvent(uploadBtn, 'click').subscribe({   next: () =&gt; upload(input.files[0]) }); <\/code><\/pre>\n<p>  <\/p>\n<h2>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0438<\/h2>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u0448 \u043a\u043e\u0434 \u043d\u0438\u0447\u0435\u043c \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f addEventListener. \u0414\u0430, \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0435\u0433\u043e \u0442\u0430\u043a\u0438\u043c, \u0442\u043e \u043f\u043e\u0442\u0435\u0440\u044f\u0435\u043c \u0442\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u043c\u0438 RxJS.<\/p>\n<p>  \u0427\u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c? \u0420\u0430\u0441\u043f\u0438\u0448\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0448\u0430\u0433\u043e\u0432 \u0434\u043b\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b\u0430:<\/p>\n<ul>\n<li>\u0412\u044b\u0431\u043e\u0440 \u0444\u0430\u0439\u043b\u0430<\/li>\n<li>\u041d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438 uploadBtn<\/li>\n<li>\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0438\u0437 input.files<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u0430<\/li>\n<\/ul>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u043d\u0430 \u043a\u043e\u0434. \u041d\u043e \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u0438 input\u2019\u0430 \u0438 uploadBtn? \u0412 \u044d\u0442\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 switchMap, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043f\u0440\u043e\u0435\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439:<\/p>\n<pre><code class=\"javascript\">fromEvent(input, 'change').pipe(     switchMap(() =&gt; fromEvent(uploadBtn, 'click')),     map(() =&gt; input.files[0]) ).subscribe({     next: file =&gt; upload(file) }); <\/code><\/pre>\n<p>  \u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439, \u0447\u0442\u043e \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0432\u044b\u0448\u0435. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0444\u0430\u0439\u043b, \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 switchMap \u0438 \u043c\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 uploadBtn. \u041d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442.<\/p>\n<p>  switchMap \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 <i>fromEvent(uploadBtn, &#8216;click&#8217;)<\/i>.\u0427\u0442\u043e\u0431\u044b \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c, \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0432\u0442\u043e\u0440\u0443\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u2014 \u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 uploadBtn. \u0417\u0430\u0442\u0435\u043c \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 map, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u0442 \u0444\u0430\u0439\u043b \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430, \u0438 \u0443\u0436\u0435 \u0432 subscribe \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 upload.<\/p>\n<p>  \u0421\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0437\u0434\u0435\u0441\u044c \u0442\u043e, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u043c\u0430. \u0427\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f upload, \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 &#8216;change&#8217;.<\/p>\n<p>  \u041d\u043e \u0432\u0441\u0435 \u0436\u0435 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u0430\u0439\u043b, \u0430 \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u044b\u0431\u043e\u0440. \u0418 \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b\u0430, \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e upload \u2014 undefined. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043d\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443:<\/p>\n<pre><code class=\"javascript\">fromEvent(input, 'change').pipe(     switchMap(() =&gt; fromEvent(uploadBtn, 'click')),     map(() =&gt; input.files[0]),     filter(file =&gt; !!file) ).subscribe({     next: file =&gt; upload(file) }); <\/code><\/pre>\n<p>  <\/p>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 xhr<\/h2>\n<p>  \u041f\u043e\u0440\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0435 \u2014 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438. \u042f \u0431\u0443\u0434\u0443 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 xhr, \u0442\u0430\u043a \u043a\u0430\u043a fetch, \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c <a href=\"https:\/\/fetch.spec.whatwg.org\/#fetch-api\">\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438<\/a>.  <\/p>\n<blockquote><p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 axios \u0438\u043b\u0438 jQuery.ajax.<\/p><\/blockquote>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e multer, \u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u043c\u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u043e\u0440\u043c\u044b(multer \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e createFormData:<\/p>\n<pre><code class=\"javascript\">function createFormData(file) {     const form = new FormData();     \/\/ \u043a\u043b\u0430\u0434\u0435\u043c \u0444\u0430\u0439\u043b \u0432 \u043f\u043e\u043b\u0435 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c file     form.append('file', file);     return form; }  fromEvent(input, 'change').pipe(     switchMap(() =&gt; fromEvent(uploadBtn, 'click')),     map(() =&gt; input.files[0]),     filter(file =&gt; !!file),     map(file =&gt; createFormData(file)) ).subscribe({     next: data =&gt; upload(data) }); <\/code><\/pre>\n<p>  \u0412\u044b\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0444\u043e\u0440\u043c\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0440\u0435\u0437 XMLHttpRequest. \u041d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0443 \u043d\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u044b unload \u0438 onerror. \u041f\u0435\u0440\u0432\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430, \u0432\u0442\u043e\u0440\u043e\u0439 \u2014 \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.<\/p>\n<pre><code class=\"javascript\">function upload(data) {     const xhr = new XMLHttpRequest();      \/\/ \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0434\u0430\u0447\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0444\u0430\u0439\u043b\u0430     xhr.onload = () =&gt; console.log('success');      \/\/ \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435     xhr.onerror = e =&gt; console.error(e);      \/\/ \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435     xhr.open('POST', '\/upload', true);      \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u043e\u0440\u043c\u0443     xhr.send(data); } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440. \u041d\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0430\u0440\u0443 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432:<\/p>\n<ul>\n<li>\u041d\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443<\/li>\n<li>\u0415\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u044c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 uploadBtn n \u0440\u0430\u0437, \u0442\u043e \u0443 \u043d\u0430\u0441 \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f n \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u043d\u0430 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430<\/li>\n<\/ul>\n<p>  \u0412\u0441\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f upload \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u043d\u0435 \u043f\u043e\u0442\u043e\u043a\u0430. \u041e\u043d\u0430 \u0436\u0438\u0432\u0435\u0442 \u0441\u0430\u043c\u0430 \u043f\u043e \u0441\u0435\u0431\u0435. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0430 \u043d\u0430\u043c Observable. \u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<pre><code class=\"javascript\">function upload(data) {     return new Observable(observer =&gt; {         const xhr = new XMLHttpRequest();          \/\/ \u043a\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u0440\u0443\u0436\u0435\u043d, \u043c\u044b \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u043e\u0431 \u044d\u0442\u043e\u043c \u0432 \u043f\u043e\u0442\u043e\u043a         \/\/ \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0435\u0433\u043e         xhr.onload = () =&gt; {             observer.next();             observer.complete();         };                  xhr.onerror = e =&gt; observer.error(e);                  xhr.open('POST', '\/upload', true);         xhr.send(data);          \/\/ \u043f\u0440\u0438 \u043e\u0442\u043f\u0438\u0441\u043a\u0435 - \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443         return () =&gt; xhr.abort();     }); } <\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0443\u044e \u0432\u043d\u0443\u0442\u0440\u0438 Observable \u0441\u0442\u0440\u0435\u043b\u043e\u0447\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0442\u043f\u0438\u0441\u043a\u0438 \u0438 \u043e\u0442\u043c\u0435\u043d\u0438\u0442 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443.<\/p>\n<p>  \u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0432\u044b\u0437\u043e\u0432 upload \u0432 switchMap:<\/p>\n<pre><code class=\"javascript\">fromEvent(input, 'change').pipe(     switchMap(() =&gt; fromEvent(uploadBtn, 'click')),     map(() =&gt; input.files[0]),     filter(file =&gt; !!file),     map(file =&gt; createFormData(file)),     switchMap(data =&gt; upload(data)) ).subscribe({     next: () =&gt; console.log('File uploaded') }); <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u043c\u0435\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0435\u0449\u0435 \u0440\u0430\u0437, \u0442\u043e \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0435\u043d, \u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439.<\/p>\n<h2>\u041e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e \u043a\u043b\u0438\u043a\u0443<\/h2>\n<p>  \u0423 \u043d\u0430\u0441 \u0435\u0449\u0435 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043a\u043d\u043e\u043f\u043a\u0430 calcelBtn. \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 takeUntil.<\/p>\n<p>  takeUntil \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u201c\u0431\u0435\u0440\u0438 \u043f\u043e\u043a\u0430\u201d. \u0414\u0430\u043d\u043d\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043e\u0442\u0434\u0430\u0435\u0442 \u0438\u0445 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435. \u0414\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u2014 takeUntil \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 unsubscribe \u0438 \u043e\u0442\u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.<\/p>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440, \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043e\u0442 \u043a\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f. \u041d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 upload, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0444\u0430\u0439\u043b\u0430, \u0442.\u0435. \u043e\u0442\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430:<\/p>\n<pre><code class=\"javascript\">fromEvent(input, 'change').pipe(     switchMap(() =&gt; fromEvent(uploadBtn, 'click')),     map(() =&gt; input.files[0]),     filter(file =&gt; !!file),     map(file =&gt; createFormData(file)),     switchMap(data =&gt; upload(data).pipe(         \/\/ \u043e\u0442\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 upload         takeUntil(fromEvent(cancelBtn, 'click'))     )) ).subscribe({     next: () =&gt; console.log('File uploaded') }); <\/code><\/pre>\n<p>  <\/p>\n<h2>Progress bar<\/h2>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c progress bar. \u0414\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 xhr.upload.onprogress. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f ProgressEvent. \u041e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0434\u043b\u044f \u043d\u0430\u0441 \u0441\u0432\u043e\u0439\u0441\u0442\u0432:<\/p>\n<ul>\n<li>lengthComputable \u2014 \u0435\u0441\u043b\u0438 true, \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043d\u0430\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430(\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 true)<\/li>\n<li>total \u2014 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0431\u0430\u0439\u0442<\/li>\n<li>loaded \u2014 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0442\u043e\u0441\u043b\u0430\u043d\u043d\u044b\u0445 \u0431\u0430\u0439\u0442<\/li>\n<\/ul>\n<p>  \u0412\u043d\u0435\u0441\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e upload:<\/p>\n<pre><code class=\"javascript\">function upload(data) {     return new Observable(observer =&gt; {         const xhr = new XMLHttpRequest();          xhr.upload.onprogress = e =&gt; {             \/\/ \u0432\u044b\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u044b             const progress = e.loaded \/ e.total * 100;             observer.next(progress);         };          xhr.onerror = e =&gt; observer.error(e);         xhr.onload = () =&gt; observer.complete();          xhr.open('POST', '\/upload', true);         xhr.send(data);          return () =&gt; xhr.abort();     }); } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c upload \u0432\u044b\u043f\u043b\u0435\u0432\u044b\u0432\u0430\u0435\u0442 \u0432 \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 style \u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 progressBar:<\/p>\n<pre><code class=\"javascript\">function setProgressBarWidth(width) {     progressBar.style.width = `${width}%`; }  fromEvent(input, 'change').pipe(    \/* ..        *\/ ).subscribe({     next: width =&gt; setProgressBarWidth(width) }); <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zq\/u5\/ji\/zqu5jisnsl6bvot5st1n3h9rule.png\">  <\/p>\n<blockquote><p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043e\u0432\u0435\u0442: \u0447\u0442\u043e\u0431\u044b \u0432\u0430\u0448\u0438 \u0444\u0430\u0439\u043b\u044b \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u043b\u0438\u0441\u044c \u043d\u0435 \u0442\u0430\u043a \u0431\u044b\u0441\u0442\u0440\u043e, \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u00abFast 3G\u00bb \u0438\u043b\u0438 \u00abSlow 3G\u00bb \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00abPerformance\u00bb \u0432 Chrome devtools.<\/p><\/blockquote>\n<h2>\u0414\u043e\u0432\u043e\u0434\u0438\u043c \u0434\u043e \u0443\u043c\u0430<\/h2>\n<p>  \u041c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0430\u0440\u0443 \u0448\u0442\u0440\u0438\u0445\u043e\u0432. \u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 uploadBtn \u043c\u044b \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e. \u041d\u043e \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0442\u043c\u0435\u043d\u044b.<\/p>\n<p>  \u0425\u043e\u0447\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043a\u043d\u043e\u043f\u043a\u0430 uploadBtn \u043d\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f, \u043f\u043e\u043a\u0430 \u043c\u044b \u043d\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0438 \u0444\u0430\u0439\u043b(\u0438\u043b\u0438 \u043f\u043e\u043a\u0430 \u043c\u044b \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u043b\u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443). \u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u044f\u0442\u044c?<\/p>\n<p>  \u041c\u043e\u0436\u043d\u043e \u0432\u0435\u0448\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 disable, \u043f\u043e\u043a\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f. \u041d\u043e \u0435\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 exhaustMap. \u0414\u0430\u043d\u043d\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430, \u043f\u043e\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d. \u0417\u0430\u043c\u0435\u043d\u0438\u043c switchMap \u043d\u0430 exhaustMap:<\/p>\n<pre><code class=\"javascript\">exhaustMap(data =&gt; upload(data).pipe(   takeUntil(fromEvent(cancelBtn, 'click')) )) <\/code><\/pre>\n<p>  \u0418 \u0432\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043d\u044b\u043c. \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<pre><code class=\"javascript\">import { fromEvent, Observable } from &quot;rxjs&quot;; import { map, switchMap, filter, takeUntil, exhaustMap } from &quot;rxjs\/operators&quot;;  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(() =&gt; fromUploadBtn),     map(() =&gt; input.files[0]),     filter(file =&gt; !!file),     map(file =&gt; createFormData(file)),     exhaustMap(data =&gt; upload(data).pipe(         takeUntil(fromCancelBtn)     )) ).subscribe({     next: width =&gt; 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 =&gt; {         const xhr = new XMLHttpRequest();          xhr.upload.onprogress = e =&gt; {             const progress = e.loaded \/ e.total * 100;             observer.next(progress);         };          xhr.onerror = e =&gt; observer.error(e);         xhr.onload = () =&gt; observer.complete();          xhr.open('POST', '\/upload', true);         xhr.send(data);          return () =&gt; xhr.abort();     }); } <\/code><\/pre>\n<p>  \u041c\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u044f \u0432\u044b\u043b\u043e\u0436\u0438\u043b <a href=\"https:\/\/github.com\/limitofzero\/upload-fiels-with-rxjs\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h2>Angular \u0438 HttpClient<\/h2>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0441 Angular, \u0442\u043e \u0432\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c xhr \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u0412 Angular \u0435\u0441\u0442\u044c HttpClient \u0441\u0435\u0440\u0432\u0438\u0441. \u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438\/\u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432 post \u043c\u0435\u0442\u043e\u0434:<\/p>\n<ul>\n<li>reportProgress: true \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435\/\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435<\/li>\n<li>observe: \u00abevents\u00bb \u2014 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c HttpEvents \u0438\u0437 \u043f\u043e\u0442\u043e\u043a\u0430<\/li>\n<\/ul>\n<p>  \u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 upload \u0432 Angular:<\/p>\n<pre><code class=\"javascript\">export class UploaderService {   constructor(private http: HttpClient) { }    public upload(data: FormData): Observable&lt;number&gt; {     return this.http.post('\/upload', data, { reportProgress: true, observe: 'events' })       .pipe(         filter(event =&gt; event.type === HttpEventType.UploadProgress),         map(event =&gt; event as HttpProgressEvent),         map(event =&gt; event.loaded \/ event.total * 100)       );   } } <\/code><\/pre>\n<p>  \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 filter \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430\u0441 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442. \u0414\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043a HttpProgressEvent, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c loaded \u0438 total. \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u043d\u0442.<\/p>\n<p>  HttpClient \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 xhr, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430 \u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 HTTP \u043f\u0440\u043e\u0449\u0435. <\/p>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Angular \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/limitofzero\/angular-upload-file-with-progress\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  RxJS \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0432 \u0440\u0443\u043a\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. \u0412 \u0435\u0433\u043e \u0430\u0440\u0441\u0435\u043d\u0430\u043b\u0435 \u0435\u0441\u0442\u044c \u043e\u0433\u0440\u043e\u043c\u043d\u0435\u0439\u0448\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043d\u0430 \u0432\u0441\u0435 \u0441\u043b\u0443\u0447\u0430\u0438 \u0436\u0438\u0437\u043d\u0438. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0438\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0432\u044b\u0441\u043e\u043a. \u0418 \u0447\u0430\u0441\u0442\u043e, \u043b\u044e\u0434\u0438 \u043f\u043e \u043d\u0435\u0437\u043d\u0430\u043d\u0438\u044e \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u00ab\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u044b\u00bb, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u043a\u043e\u0434 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0442\u0440\u0443\u0434\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c.<\/p>\n<p>  \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u043e\u0436\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435\u043c \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f\u043c, \u043d\u0435 \u0441\u0442\u043e\u044f\u0442\u044c \u043d\u0430 \u043c\u0435\u0441\u0442\u0435 \u0438 \u043d\u0435 \u0431\u043e\u044f\u0442\u044c\u0441\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0418\u0437\u0443\u0447\u0430\u0439\u0442\u0435 RxJS. \u0412\u0434\u0440\u0443\u0433 \u0432\u044b \u043d\u0430\u0442\u043a\u043d\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c 10 \u0441\u0442\u0440\u043e\u0447\u0435\u043a \u043a\u043e\u0434\u0430 \u0432 \u043e\u0434\u043d\u0443. \u0418\u043b\u0438 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0447\u0443\u0442\u043e\u0447\u043a\u0443 \u043f\u043e\u043d\u044f\u0442\u043d\u0435\u0439.<\/p>\n<p>  \u0423\u0434\u0430\u0447\u0438!<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/487836\/\"> https:\/\/habr.com\/ru\/post\/487836\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/487836\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oo\/ei\/f7\/ooeif7l8-qpd0wfxxriskilepha.png\"><\/p>\n<p>  \u041f\u0440\u043e\u0448\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440, \u043a\u0430\u043a \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c RxJS. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043c\u0435\u043d\u044f \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043e\u0440\u0438\u044e \u0438 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0444\u0430\u0439\u043b\u043e\u0432.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-298482","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/298482","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=298482"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/298482\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=298482"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=298482"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=298482"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}