<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Arseniy Tomkevich on Medium]]></title>
        <description><![CDATA[Stories by Arseniy Tomkevich on Medium]]></description>
        <link>https://medium.com/@jsmuster?source=rss-5ee60ea6c196------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*vuya5-YRRodHOG93lQgFtg.jpeg</url>
            <title>Stories by Arseniy Tomkevich on Medium</title>
            <link>https://medium.com/@jsmuster?source=rss-5ee60ea6c196------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:47:09 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@jsmuster/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Setting Up and Managing Persistent Volumes with Longhorn in Your Kubernetes Cluster]]></title>
            <link>https://levelup.gitconnected.com/setting-up-and-managing-persistent-volumes-with-longhorn-in-your-kubernetes-cluster-6f6dc95d01fa?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f6dc95d01fa</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[application]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Sun, 04 Aug 2024 17:28:47 GMT</pubDate>
            <atom:updated>2024-08-04T17:28:47.879Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Scat2PojdVqsIu63" /></figure><p>Continuing with the Kubernetes adventure I realized my setup had flaws. I couldn’t access the localhost within a multipass VM from my host (Mac), and I had difficulty setting up persistent storage for my cluster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*G8kHFEVIpt0hiNSr" /></figure><p>Here is a link to my first article <strong>Setting up your own Kubernetes Cluster with Multipass — A Step by Step Guide</strong>:<br><a href="https://medium.com/gitconnected/setting-up-kubernetes-cluster-with-multipass-on-a-mac-a-step-by-step-guide-4645f8f30c45">https://medium.com/gitconnected/setting-up-kubernetes-cluster-with-multipass-on-a-mac-a-step-by-step-guide-4645f8f30c45</a></p><p>Today we’ll continue with getting up and running the Persistent Volumes (PVs) and Persistent Volume Claims (PVCs), while bringing in Longhorn for some fancy, reliable storage magic. Get ready to supercharge our local Kubernetes setup!</p><p>To give Kubernetes apps disk storage, we are going to need Persistent Volumes. While <strong>HostPath</strong> and <strong>LocalPersistentVolumes</strong> work, they’re limited to single nodes and fail if the node does. For more reliable, redundant storage, Longhorn comes to the rescue!</p><h4><strong>Why Longhorn?</strong></h4><p>You have two main choices for self-hosted PersistentVolumes. Rook offers a powerful CEPH-based solution with block storage, but it needs extra drives, which isn’t great for smaller setups.</p><p>Longhorn, on the other hand, uses HostPath volumes and adds a layer to turn them into fault-tolerant PersistentVolumes. It spreads data across nodes to keep it safe from failures and manages storage that way, leaving room for system files and container caches.</p><h4><strong>Key Features of HostPath Volumes</strong></h4><p>HostPath volumes give containers direct access to files on the node, which is useful for sharing files or logs between container and the host.</p><p><strong>Generally Not for Production</strong>: HostPath Volumes are not recommended for production because they tie your pod to a specific node. Due to immutable architecture of Kubernetes, the pod will not have access to the same HostPath volume if its rescheduled to a different node, which causes issues with data consistency.</p><p><strong>BUT</strong> <strong>Longhorn</strong> while using HostPath volumes as part of its underlying architecture abstracts away many of the complexities and limitations of raw HostPath volumes to make them suitable for production environments.</p><p>Longhorn <strong>replicates data across multiple nodes</strong>, providing redundancy and fault tolerance. This actually makes it suitable for production environments where data availability is critical.</p><p>It automates many aspects of storage management, including provisioning, backups, and snapshots, simplifying storage operations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/873/0*73cYbjo0l2Krlqk5" /></figure><h3>Getting Longhorn Installed</h3><p>Getting Longhorn up and running is a no brainer! It mostly takes care of itself, but you need to have open-iscsi and NFSv4 on each node. Instead of manually installing these on every single node, we are going to use <strong>DaemonSet</strong> to automate the process. DaemonSets are Kubernetes API objects that allow you to run Pods as a daemon on each of your Nodes. It’s quick and easy!</p><p>Just run this command within the kubemaster, all of our kubectl commands should run there:</p><pre>kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.2/deploy/prerequisite/longhorn-iscsi-installation.yaml<br>kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.2/deploy/prerequisite/longhorn-nfs-installation.yaml</pre><p>The installation might take a minute to wrap up. You can keep an eye on the progress with these commands:</p><pre>kubectl get pod | grep longhorn-iscsi-installation<br><br>kubectl get pod | grep longhorn-nfs-installation</pre><p>These commands show you the details of pods related to the Longhorn iSCSI installation by filtering out other pods from the list.</p><pre># You should see something like:<br><br>longhorn-nfs-installation-flnhs     1/1     Running   2 (10h ago)   14h<br>longhorn-nfs-installation-sfhmr     1/1     Running   2 (10h ago)   14h</pre><p>After installing the dependencies, you’re ready to install Longhorn itself.</p><pre>kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.2/deploy/longhorn.yaml</pre><p>to monitor the progress use the — watch flag:</p><pre>kubectl get pods -n longhorn-system --watch</pre><p>Once ready, you should see a similar output:</p><pre>NAME                                                READY   STATUS    RESTARTS      AGE<br>csi-attacher-6d8779d485-6nk6t                       1/1     Running   5 (9h ago)    14h<br>csi-attacher-6d8779d485-6qcng                       1/1     Running   2 (10h ago)   14h<br>csi-attacher-6d8779d485-dwxr9                       1/1     Running   1 (10h ago)   14h<br>csi-provisioner-69ffbb8c5b-2l7k7                    1/1     Running   2 (10h ago)   14h<br>csi-provisioner-69ffbb8c5b-5zcrr                    1/1     Running   3 (9h ago)    14h<br>csi-provisioner-69ffbb8c5b-ffbkg                    1/1     Running   4 (9h ago)    14h<br>csi-resizer-7b98f6fbc4-gs7zk                        1/1     Running   1 (10h ago)   14h<br>csi-resizer-7b98f6fbc4-hxshw                        1/1     Running   5 (9h ago)    14h<br>csi-resizer-7b98f6fbc4-ph6ms                        1/1     Running   2 (10h ago)   14h<br>csi-snapshotter-65d845d4f4-8bnp6                    1/1     Running   2 (10h ago)   14h<br>csi-snapshotter-65d845d4f4-gg5hl                    1/1     Running   5 (9h ago)    14h<br>csi-snapshotter-65d845d4f4-xg5mb                    1/1     Running   2 (10h ago)   14h<br>engine-image-ei-65224a4b-2fqjq                      1/1     Running   2 (10h ago)   14h<br>engine-image-ei-65224a4b-7brjg                      1/1     Running   1 (10h ago)   14h<br>instance-manager-84d479227caee7de34d45408517eeca0   1/1     Running   0             10h<br>instance-manager-ba2939744e154f4f95b7a2e527d76378   1/1     Running   0             10h<br>longhorn-csi-plugin-nd224                           3/3     Running   8 (10h ago)   14h<br>longhorn-csi-plugin-r48fx                           3/3     Running   4 (10h ago)   14h<br>longhorn-driver-deployer-74bf9cb677-f45fm           1/1     Running   3 (10h ago)   14h<br>longhorn-manager-kqk9k                              1/1     Running   1 (10h ago)   14h<br>longhorn-manager-x2ld9                              1/1     Running   2 (10h ago)   14h<br>longhorn-ui-fd949ccd4-24ghm                         1/1     Running   1 (10h ago)   14h<br>longhorn-ui-fd949ccd4-w2gdb                         1/1     Running   2 (10h ago)   14h</pre><p><strong>csi-attacher<br></strong>The CSI Attacher is responsible for attaching volumes to nodes. It works in conjunction with the Kubernetes Controller Manager to ensure that volumes are properly attached to the correct nodes.</p><p><strong>csi-provisioner<br></strong>The CSI Provisioner handles the management of PersistentVolumes (PVs) based on PersistentVolumeClaims (PVCs). It ensures that storage resources are allocated and deallocated as required per the PVCs.</p><p><strong>csi-resizer</strong><br>The CSI Resizer manages the resizing of volumes. When a PVC requests a larger volume, the Resizer adjusts the size of the underlying PersistentVolume to accommodate the request.</p><p><strong>csi-snapshotter</strong><br>CSI Snapshotter handles the creation and management of volume snapshots. It enables backup and restore operations by taking snapshots of the volume data.</p><p><strong>engine-image-ei</strong><br>This component manages Longhorn engine images. Engine images are used to create and manage the Longhorn storage engines that interact with volumes.</p><p><strong>instance-manager</strong><br>Instance Managers are responsible for managing Longhorn volumes and their associated instances. They handle tasks like provisioning and maintaining the Longhorn volumes’ instances.</p><p><strong>longhorn-csi-plugin</strong><br>The Longhorn CSI Plugin interfaces with the Kubernetes CSI (Container Storage Interface) to provide Longhorn volumes to Kubernetes pods. It acts as a bridge between Kubernetes and the Longhorn storage system.</p><p><strong>longhorn-driver-deployer</strong><br>This pod deploys and manages the Longhorn driver components. It ensures that the necessary drivers are correctly set up and operational within the Kubernetes cluster.</p><p><strong>longhorn-manager</strong><br>The Longhorn Manager oversees the overall operation of the Longhorn system. It manages volume operations, health monitoring, and configuration tasks.</p><p><strong>longhorn-ui</strong><br>This pod runs the Longhorn user interface, providing a web-based dashboard for managing Longhorn storage, viewing volume status, and performing administrative tasks.</p><h4><strong>Check if Volumes are Working</strong></h4><p>To confirm that installation was successful and your storage is ready, create a <strong>PersistentVolumeClaim</strong>. This will prompt Longhorn to automatically provision a <strong>PersistentVolume</strong>, which takes care of that headache for you.</p><p>The same will work with deleting, Longhorn will remove the <strong>PersistentVolume</strong> once you delete the <strong>PersistentVolumeClaim</strong>.</p><p>At first I was manually setting up my own PVs and PVCs but various reasons Kubernetes had trouble managing them, especially deleting the volumes and I had to use all sorts of tricks to force Kubernetes do what I want.</p><p>For example a PV would get stuck Terminating and hang there, which meant I couldn’t create a PV with the same name and had to wait:</p><pre>NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS        CLAIM                                         STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE<br>c-registry-pv 5Gi        RWO            Retain           Terminating   cybernetically-utils/container-registry-pvc   standard       &lt;unset&gt;</pre><p>Longhorn makes all these problems go away, the modules I described above do all the management.</p><p>Here’s an example, this YAML defines a <strong>PersistentVolumeClaim</strong> named container-registry-pvc that requests 1GB of read-write storage from Longhorn, which will handle provisioning the actual <strong>PersistentVolume</strong>.</p><pre>apiVersion: v1<br>kind: PersistentVolumeClaim<br>metadata:<br>  namespace: container-registry-pvc<br>  name: longpvc<br>spec:<br> accessModes:<br>   - ReadWriteOnce<br> resources:<br>   requests:<br>     storage: 1Gi<br> storageClassName: longhorn</pre><p>Save this into “longhorn-pvc.yaml” and apply the Yaml file</p><pre>kubectl apply -f longhorn-pvc.yaml</pre><p>Inspect the claim by running:</p><pre>kubectl describe pvc longpvc</pre><p>You should see something like this, the most important part is the <strong>Status</strong> which should be <strong>Bound</strong>.</p><pre>Name:          container-registry-pvc<br>Namespace:     default<br>StorageClass:  longhorn<br>Status:        Bound<br>Volume:        pvc-d462441d-0348-4325-a90c-f783a4481547<br>Labels:        &lt;none&gt;<br>Annotations:   pv.kubernetes.io/bind-completed: yes<br>               pv.kubernetes.io/bound-by-controller: yes<br>               volume.beta.kubernetes.io/storage-provisioner: driver.longhorn.io<br>               volume.kubernetes.io/storage-provisioner: driver.longhorn.io<br>Finalizers:    [kubernetes.io/pvc-protection]<br>Capacity:      1Gi<br>Access Modes:  RWO<br>VolumeMode:    Filesystem<br>Used By:       &lt;none&gt;<br>Events:        &lt;none&gt;</pre><h4><strong>LongHorn Dashboard</strong></h4><p>Longhorn has a dashboard and you can access it by port forwarding from your multipass into your host, but there is trick with our setup.</p><p>I’ve spent many hours trying to figure this part out and apparently multipass has a problem with forwarding TCP6 requests that are coming from a host into the multipass VM.</p><p>I could ping my multipass VM, which I believe uses the TCP4, but I couldn’t access the localhost which uses TCP6, so I used the following technique to make it work.</p><p>First, port forward the long-horn frontend by running on the kubemaster.</p><pre>kubectl port-forward service/longhorn-frontend -n longhorn-system 8080:80</pre><p>Now the longhorn front end will be available for access within kubemaster, but we want to access it on a host through the browser. I have searched the internet for a couple of days and the only thing I found is that TCP6 requests are not forwarded by multipass. So here is the trick:</p><p>Install socat on kubemaster</p><pre>sudo apt-get update<br>sudo apt-get install socat</pre><p>And then have socat forward the TCP6 requests, thats it! At this point you are port forwarding from Kubernetes into the VM and from VM into the host.</p><pre>kubemaster -- sudo socat &quot;TCP6-LISTEN:8088&quot;,fork &quot;TCP6:[::1]:8080&quot;</pre><p>For ease of use, you can run the above command via <strong>multipass exec</strong> from the host:</p><pre>multipass exec -n kubemaster -- kubemaster -- sudo socat &quot;TCP6-LISTEN:8088&quot;,fork &quot;TCP6:[::1]:8080&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/533/1*yNZIPQo0k19vvRdc6Q4Biw.png" /></figure><p>Once executed, now point the browser to 8088 port of your kubemaster, for example my browser URL is http://192.168.64.100:8088 and you should see the longhorn control panel:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fJc2gDfTFHrtXFAmcVbLIg.png" /></figure><p>Another way to expose the front end is by editing the <strong>service/longhorn-frontend</strong>:</p><pre>kubectl edit service/longhorn-frontend -n longhorn-system</pre><p>You should change the type to a <strong>NodePort</strong> as bellow:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/679/1*kzG0S7epKMZZn0nZlgf7Hw.png" /></figure><p>Find the name of the kubernetes longhorn dashboard pod, run this command:</p><pre>kubectl get pods -n longhorn-system</pre><p>You should see a pod it starts with longhorn-ui for example:</p><pre>longhorn-ui-fd949ccd4-24ghm                         1/1     Running   5 (93m ago)     3d13h<br>longhorn-ui-fd949ccd4-w2gdb                         1/1     Running   7 (93m ago)     3d13h</pre><p>Whenever you modify the service type, you must delete the pod. Kuberntes creates a new one for you, essentially restarting the pod. So lets run these commands (make sure you use your pod uids you got from the previous command):</p><pre>kubectl delete pod longhorn-ui-fd949ccd4-24ghm -n longhorn-system<br>kubectl delete pod longhorn-ui-fd949ccd4-w2gdb -n longhorn-system</pre><p>Now to make sure Kubernetes restarted the pods run the command, you should see another set of pods starting:</p><pre>kubectl get pods -n longhorn-system</pre><p>Verify that the service is of a correct type and run this command:</p><pre>kubectl get svc -n longhorn-system</pre><p>You should see this:</p><pre>NAME                          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE<br>longhorn-admission-webhook    ClusterIP   10.101.1.14      &lt;none&gt;        9502/TCP       3d13h<br>longhorn-backend              ClusterIP   10.106.19.214    &lt;none&gt;        9500/TCP       3d13h<br>longhorn-conversion-webhook   ClusterIP   10.103.237.212   &lt;none&gt;        9501/TCP       3d13h<br>longhorn-engine-manager       ClusterIP   None             &lt;none&gt;        &lt;none&gt;         3d13h<br>longhorn-frontend             NodePort    10.96.49.169     &lt;none&gt;        80:32628/TCP   3d13h<br>longhorn-recovery-backend     ClusterIP   10.104.4.107     &lt;none&gt;        9503/TCP       3d13h<br>longhorn-replica-manager      ClusterIP   None             &lt;none&gt;        &lt;none&gt;         3d13h</pre><p>Now open your favorite browser and navigate to a URL, where 192.168.64.100 is the kubemaster static IP.</p><p>https://192.168.64.100:32628</p><h3>Wrap up</h3><p>We’ve successfully set up Longhorn for Persistent Volumes in our Kubernetes cluster, boosting the local development setup with reliable, fault-tolerant storage.</p><p>With Longhorn’s automation and robust features, managing storage has never been easier!</p><p>If you’ve navigated any challenges or have questions, feel free to reach out.</p><p>Happy deploying!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f6dc95d01fa" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/setting-up-and-managing-persistent-volumes-with-longhorn-in-your-kubernetes-cluster-6f6dc95d01fa">Setting Up and Managing Persistent Volumes with Longhorn in Your Kubernetes Cluster</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Setting up Kubernetes Cluster with Multipass on A Mac — A Step by Step Guide]]></title>
            <link>https://levelup.gitconnected.com/setting-up-kubernetes-cluster-with-multipass-on-a-mac-a-step-by-step-guide-4645f8f30c45?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/4645f8f30c45</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[application-development]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[infrastructure-as-code]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Tue, 16 Jul 2024 16:31:58 GMT</pubDate>
            <atom:updated>2024-07-16T16:31:58.932Z</atom:updated>
            <content:encoded><![CDATA[<h3>Setting up your own Kubernetes Cluster with Multipass — A Step by Step Guide</h3><p>Have you ever wanted to build your own Kubernetes setup? In this article I will take you on an ambitious journey to create a scalable infrastructure from scratch, a local AWS if you like. This endeavor was driven by a desire for hands-on experience and a deeper understanding of Kubernetes’ inner workings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Af3pNNv8PPHqrD5z0gYlLA.png" /></figure><p>I will be using a Mac but I don’t think that matters much, because all of these commands and configuration can be useful on any platform where you can run Multipass because a lot of settings are applied to VMs themselves.</p><p>In Multipass, VMs are assigned dynamic IP addresses, that can change after a reboot. This behavior can disrupt a Kubernetes cluster, as changing IP addresses interfere with cluster communication and stability. Therefore, it is crucial to provision VMs with static IP addresses.</p><h4>Setting up a new bridge with a static IP on the Mac</h4><p>Here I go creating a new bridge with a static IP on my host.</p><p>To create a new bridge with a static IP on macOS, you can use the built-in ifconfig utility and modify network settings accordingly. Here is a step-by-step guide:</p><h3>Create the Bridge Interface</h3><p>Open Terminal.</p><p>Use the ifconfig command to create a new bridge interface. This example will use bridge0.</p><pre>sudo ifconfig bridge0 create</pre><p>Add the physical network interface to the bridge. Replace en0 with your network interface name.</p><pre>sudo ifconfig bridge0 addm en0</pre><h4>Step 2: Configure the Bridge with a Static IP</h4><p>Assign a static IP to the bridge. Replace 192.168.1.2 with your desired IP address and 255.255.255.0 with your subnet mask.</p><pre>sudo ifconfig bridge0 inet 192.168.1.2 netmask 255.255.255.0 up</pre><p>Set the default gateway if needed. Replace 192.168.1.1 with your gateway IP.</p><pre>sudo route add default 192.168.1.1</pre><h4>Step 3: Persist Configuration</h4><p>To make these changes persistent across reboots, you need to create a launch daemon.</p><p>Create a new launch daemon plist file in /Library/LaunchDaemons/. For example, com.local.bridge.plist.</p><pre>sudo nano /Library/LaunchDaemons/com.local.bridge.plist</pre><p>Add the following content to the plist file:</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;<br>&lt;plist version=&quot;1.0&quot;&gt;<br>&lt;dict&gt;<br>    &lt;key&gt;Label&lt;/key&gt;<br>    &lt;string&gt;com.local.bridge&lt;/string&gt;<br>    &lt;key&gt;ProgramArguments&lt;/key&gt;<br>    &lt;array&gt;<br>        &lt;string&gt;/usr/sbin/ifconfig&lt;/string&gt;<br>        &lt;string&gt;bridge0&lt;/string&gt;<br>        &lt;string&gt;create&lt;/string&gt;<br>        &lt;string&gt;addm&lt;/string&gt;<br>        &lt;string&gt;en0&lt;/string&gt;<br>        &lt;string&gt;inet&lt;/string&gt;<br>        &lt;string&gt;192.168.1.2&lt;/string&gt;<br>        &lt;string&gt;netmask&lt;/string&gt;<br>        &lt;string&gt;255.255.255.0&lt;/string&gt;<br>        &lt;string&gt;up&lt;/string&gt;<br>    &lt;/array&gt;<br>    &lt;key&gt;RunAtLoad&lt;/key&gt;<br>    &lt;true/&gt;<br>&lt;/dict&gt;<br>&lt;/plist&gt;</pre><p>Set the appropriate permissions for the plist file.</p><pre>sudo chown root:wheel /Library/LaunchDaemons/com.local.bridge.plist<br>sudo chmod 644 /Library/LaunchDaemons/com.local.bridge.plist</pre><p>Load the plist file to apply the settings.</p><pre>sudo launchctl load /Library/LaunchDaemons/com.local.bridge.plist</pre><h4>Step 4: Verify the Configuration</h4><p>Check that the bridge is active and has the correct IP configuration.</p><pre>ifconfig bridge0</pre><p>This process sets up a network bridge with a static IP on macOS Monterey, and the configuration persists across reboots.</p><h3>Setup a Control-Plane Instance</h3><p>A control-plane is essentially the VM thats going to be the master within our cluster, it will coordinate and schedule jobs on other nodes within the cluster.</p><p>We need to launch a virtual machine instance using Multipass.</p><p>We are going to call it <strong>kubemaster</strong> and put it on the en0 network. We’ll allocate 10gb of disk space for the instance and 3gb RAM, 2CPU cores and thats going to be using the base name “Jammy” which reffers to the codename for Ubuntu 22.04 LTS (Jammy Jellyfish)</p><pre>multipass launch --disk 10G --memory 3G --cpus 2 --name kubemaster --network name=en0,mode=manual,mac=&quot;02:42:ac:11:00:02&quot; jammy</pre><p>You should see the kubemaster spinning up and then<br><strong>Launched: kubemaster</strong></p><p>Run the command to see the kubemaster IP address:<br>multipass list or you could actually shell into the instance with multipass shell kubemaster</p><p>My IP address for kubemaster is <strong>192.168.64.4</strong>. So the static IP should end with <strong>100</strong>, but when setting up you can pick your own IP, so let’s configure the extra interface for the instance.</p><p>Just run this command, which executes multipass exec, which means it will execute this command within the kubemaster instance</p><pre>multipass exec kubemaster -- sudo bash -c &#39;cat &lt;&lt; EOF &gt; /etc/netplan/10-custom.yaml<br>network:<br>  version: 2<br>  ethernets:<br>    extra0:<br>      dhcp4: no<br>      match:<br>        macaddress: &quot;52:54:00:d5:d5:11&quot;<br>      addresses: [192.168.64.100/24]<br>EOF&#39;</pre><p>Then run this to apply the configuration, which will run another command within the kubemaster instance</p><pre>multipass exec -n kubemaster - sudo netplan apply</pre><p>You should get this output, ignore any warnings</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/822/1*5ZlpK_RXCNfRd-5B_xvSOA.png" /></figure><p>Go ahead and confirm that its working, run this command:</p><pre>multipass info kubemaster</pre><p><strong>You should see this type of output:</strong></p><pre>Name: kubemaster<br>State: Running<br>Snapshots: 0<br>IPv4: 192.168.64.5<br> 192.168.64.100<br>Release: Ubuntu 22.04.4 LTS<br>Image hash: 769f0355acc3 (Ubuntu 22.04 LTS)<br>CPU(s): 2<br>Load: 0.00 0.00 0.00<br>Disk usage: 1.6GiB out of 9.6GiB<br>Memory usage: 180.8MiB out of 2.9GiB</pre><p>Go ahead and ping these IPs to make sure everything is in order</p><pre>ping 192.168.64.5<br>ping 192.168.64.100</pre><p>You can also execute a command from within the instance and ping your local machine, make sure to replace the following IP with your local host IP</p><pre><br>multipass exec -n kubemaster -- ping 192.168.132.63<br><br>PING 192.168.132.63 (192.168.132.63) 56(84) bytes of data.<br>64 bytes from 192.168.132.63: icmp_seq=1 ttl=64 time=0.835 ms<br>64 bytes from 192.168.132.63: icmp_seq=2 ttl=64 time=0.797 ms<br>64 bytes from 192.168.132.63: icmp_seq=3 ttl=64 time=0.735 ms<br>64 bytes from 192.168.132.63: icmp_seq=4 ttl=64 time=0.511 ms<br>64 bytes from 192.168.132.63: icmp_seq=5 ttl=64 time=0.627 ms<br>64 bytes from 192.168.132.63: icmp_seq=6 ttl=64 time=0.999 ms<br>64 bytes from 192.168.132.63: icmp_seq=7 ttl=64 time=0.826 ms<br>64 bytes from 192.168.132.63: icmp_seq=8 ttl=64 time=0.767 ms<br>64 bytes from 192.168.132.63: icmp_seq=9 ttl=64 time=0.758 ms<br>64 bytes from 192.168.132.63: icmp_seq=10 ttl=64 time=1.03 ms</pre><h3>Create both mules</h3><p>Now we’ll go ahead and setup both of our mule nodes <strong>kubesmule101</strong> &amp; <strong>kubesmule102</strong></p><p>Run these commands one after the other:</p><pre>multipass launch --disk 10G --memory 3G --cpus 2 --name kubesmule01 --network name=en0,mode=manual,mac=&quot;44:33:00:4b:ba:e1&quot; jammy<br><br>multipass launch --disk 10G --memory 3G --cpus 2 --name kubesmule02 --network name=en0,mode=manual,mac=&quot;44:33:00:4b:cd:ee&quot; jammy</pre><p>After that run these commands to make sure both instances have been created:</p><pre>multipass info kubesmule01<br><br>multipass info kubesmule02</pre><p>You should see this in the output</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/394/1*0ISN6Ou800TRlRfi67YrkQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/362/1*lOo4f6w70fTymYyK54v_-w.png" /></figure><p>Notice the IPs I have here are 192.168.64.X, we’ll use this, now lets create an extra interface for both of these instances by running these commands. Here we are running the command within each instance that assigns it a static IP, I used 192.168.64.120 and 192.168.64.130:</p><pre>multipass exec -n kubesmule01 -- sudo bash -c &#39;cat &lt;&lt; EOF &gt; /etc/netplan/10-custom.yaml<br>network:<br>  version: 2<br>  ethernets:<br>    extra0:<br>      dhcp4: no<br>      match:<br>        macaddress: &quot;44:33:00:4b:ba:e1&quot;<br>      addresses: [192.168.64.120/24]<br>EOF&#39;<br><br><br>multipass exec -n kubesmule02 -- sudo bash -c &#39;cat &lt;&lt; EOF &gt; /etc/netplan/10-custom.yaml<br>network:<br>  version: 2<br>  ethernets:<br>    extra0:<br>      dhcp4: no<br>      match:<br>        macaddress: &quot;44:33:00:4b:cd:ee&quot;<br>      addresses: [192.168.64.130/24]<br>EOF&#39;</pre><p>Run these commands to apply the configuration:</p><pre>multipass exec -n kubesmule01 -- sudo netplan apply<br><br>multipass exec -n kubesmule02 -- sudo netplan apply</pre><p>Lets check if our instances have static IPs, run this:</p><pre>multipass info kubesmule01<br>multipass info kubesmule02</pre><p>You should see two IPs in the output of each command:</p><pre>Name:           kubesmule01<br>State:          Running<br>Snapshots:      0<br>IPv4:           192.168.64.7<br>                192.168.64.120<br>Release:        Ubuntu 22.04.4 LTS<br>Image hash:     769f0355acc3 (Ubuntu 22.04 LTS)<br>CPU(s):         2<br>Load:           0.00 0.00 0.00<br>Disk usage:     1.6GiB out of 9.6GiB<br>Memory usage:   173.8MiB out of 2.9GiB<br><br>Name:           kubesmule02<br>State:          Running<br>Snapshots:      0<br>IPv4:           192.168.64.8<br>                192.168.64.130<br>Release:        Ubuntu 22.04.4 LTS<br>Image hash:     769f0355acc3 (Ubuntu 22.04 LTS)<br>CPU(s):         2<br>Load:           0.00 0.00 0.00<br>Disk usage:     1.6GiB out of 9.6GiB<br>Memory usage:   182.5MiB out of 2.9GiB</pre><p>Now for the final test, lets ping all of these IPs from the local host and ping the local host from within each instance:</p><pre>ping 192.168.64.7<br>ping 192.168.64.120<br><br>ping 192.168.64.8<br>ping 192.168.64.130<br><br>multipass exec -n kubesmule01 -- ping 192.168.132.63<br><br>multipass exec -n kubesmule02 -- ping 192.168.132.63</pre><h3>Configuring the local DNS</h3><p>Now we have to change the hosts file inside each of the instances in order to configure the local DNS for each of the instances, you can do it one after the other or just open three Terminal tabs and do it in paralell:</p><pre>multipass shell kubemaster<br>multipass shell kubesmule01<br>multipass shell kubesmule02</pre><p>Run the following command in each instance:</p><pre>sudo vi /etc/hosts</pre><p>and add this information to the file. If you aren’t familiar with <strong>vi</strong> then press “<strong>a</strong>” once you enter the editor to start editing the file, once done press “<strong>Esc</strong>” and “<strong>:wq</strong>” to save and exit vi.</p><pre>192.168.64.100 kubemaster<br>192.168.64.120 kubemule01<br>192.168.64.130 kubemule02</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/476/1*3yQHuCrMWP375rTxHB47RQ.png" /></figure><p>Now that we are done with setting up our instances, time to setup Kubernetes itself.</p><h3><strong>Finally, Setting up Kubernetes</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8KPOQLKmodwMQ9W5" /></figure><p>Open up 3 terminals and shell inside each of the instances like this and run the following commands in each of the instances:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ehs2xbUlFWg2wDRsdEgnUg.png" /></figure><p>The following commands are used to configure a Linux system for Kubernetes (k8s) setup by ensuring necessary kernel modules are loaded and sysctl parameters are set correctly. Here’s a breakdown of what each part does:</p><p><strong>Loading Kernel Modules (</strong><strong>k8s.conf)</strong>:</p><pre>cat &lt;&lt;EOF | sudo tee /etc/modules-load.d/k8s.conf<br>overlay<br>br_netfilter<br>EOF</pre><ul><li>This command writes the strings overlay and br_netfilter to the file /etc/modules-load.d/k8s.conf.</li><li>These modules (overlay and br_netfilter) are required by Kubernetes for networking and container runtime management.</li></ul><pre>sudo modprobe overlay<br>sudo modprobe br_netfilter</pre><ul><li>These commands manually load the kernel modules overlay and br_netfilter into the kernel immediately after adding them to the configuration file.</li><li>modprobe is used to load kernel modules into the kernel dynamically.</li></ul><p><strong>Setting Sysctl Parameters (</strong><strong>k8s.conf)</strong>:</p><pre>cat &lt;&lt;EOF | sudo tee /etc/sysctl.d/k8s.conf<br>net.bridge.bridge-nf-call-iptables  = 1<br>net.bridge.bridge-nf-call-ip6tables = 1<br>net.ipv4.ip_forward                 = 1<br>EOF</pre><ul><li>This command writes the specified sysctl parameters to the file /etc/sysctl.d/k8s.conf.</li><li>These parameters (net.bridge.bridge-nf-call-iptables, net.bridge.bridge-nf-call-ip6tables, and net.ipv4.ip_forward) are required for Kubernetes networking and IP forwarding.</li></ul><pre>sudo sysctl --system</pre><ul><li>This command applies the changes made in /etc/sysctl.d/k8s.conf immediately without needing a system reboot.</li><li>It reads and applies sysctl settings from all files under /etc/sysctl.d/ and /run/sysctl.d/.</li></ul><p><strong>Verification</strong>:</p><ul><li>After configuring the modules and sysctl parameters, the script verifies if everything is set correctly.</li></ul><pre>lsmod | grep br_netfilter<br>lsmod | grep overlay</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/808/1*Ys5xR72RINUZ2sO6_9JJnw.png" /></figure><p>These commands check if the kernel modules br_netfilter and overlay are currently loaded.</p><pre>sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward</pre><p>This command verifies that the sysctl parameters net.bridge.bridge-nf-call-iptables, net.bridge.bridge-nf-call-ip6tables, and net.ipv4.ip_forward are set to 1 as expected.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/820/1*t7UqhDLhblZKH4yHqLMnJg.png" /></figure><p>In summary, we’ve automated the configuration steps required to set up Linux for running Kubernetes, ensuring that necessary kernel modules are loaded and sysctl parameters are correctly configured. These steps are essential for Kubernetes to manage networking and IP forwarding effectively on the host system.</p><p>Now that the networking is setup, we can setup the runtime.</p><h3>Setting up the Instance Runtime</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*zVxwwGnjkI2ZzBzn" /></figure><p>We will be configuring <strong>containerd</strong>, an industry-standard container runtime recognized for its simplicity, robustness, and portability.</p><p>As a daemon, containerd oversees the entire container lifecycle on its host system, encompassing tasks from image transfer and storage to container execution and supervision, as well as low-level storage management and network attachments.</p><p>We’ll be using the latest version <strong>1.7.14, </strong>so lets execute the following commands on every instance, but first you need to understand your current system architecture, execute “<strong>uname -m</strong>” to find out. Mine is <strong><em>x86_64</em></strong>, which means we’ll be installing the <strong><em>amd64</em></strong> versions of containerd. You can find these links here <a href="https://github.com/containerd/containerd/releases">https://github.com/containerd/containerd/releases</a></p><pre># Download containerd binaries:<br>curl -LO https://github.com/containerd/containerd/releases/download/v1.7.19/containerd-1.7.19-linux-amd64.tar.gz<br><br># Extract containerd binaries to /usr/local/:<br>sudo tar Cxzvf /usr/local containerd-1.7.19-linux-amd64.tar.gz<br><br># Download containerd systemd service file:<br>curl -LO https://raw.githubusercontent.com/containerd/containerd/main/containerd.service<br><br># Move systemd service file to appropriate directory:<br>sudo mkdir -p /usr/local/lib/systemd/system/<br>sudo mv containerd.service /usr/local/lib/systemd/system/<br><br># Configure containerd with default settings:<br>sudo mkdir -p /etc/containerd/<br>sudo containerd config default | sudo tee /etc/containerd/config.toml &gt; /dev/null<br><br># Modify containerd configuration file to enable systemd cgroup integration:<br>sudo sed -i &#39;s/SystemdCgroup \= false/SystemdCgroup \= true/g&#39; /etc/containerd/config.toml<br><br># Reload systemd manager configuration:<br>sudo systemctl daemon-reload<br><br># Enable and start containerd service:<br>sudo systemctl enable --now containerd<br><br># Check status of containerd service:<br>systemctl status containerd</pre><p><strong><em>Here is the break down of these commands:</em></strong></p><ol><li><strong>Download containerd binaries:</strong></li></ol><pre>curl -LO https://github.com/containerd/containerd/releases/download/v1.7.19/containerd-1.7.19-linux-amd64.tar.gz</pre><ul><li>We need to obtain the containerd binaries to install and configure containerd on these Linux instances. So we use curl to download the containerd binary</li></ul><p><strong>2. Extract containerd binaries to /usr/local/:</strong></p><pre>sudo tar Cxzvf /usr/local containerd-1.7.19-linux-amd64.tar.gz</pre><ul><li>Here we use atar tool for handling archives to extract (x), compress (z), and show verbose output (v) of the contents of the containerd-1.7.14-linux-arm64.tar.gz file. The C flag ensures the operation is executed in /usr/local/</li><li>By extracting the binaries to /usr/local/, you make them accessible system-wide, allowing containerd to be executed from anywhere on your system.</li></ul><p><strong>3. Download containerd systemd service file:</strong></p><pre>curl -LO https://raw.githubusercontent.com/containerd/containerd/main/containerd.service</pre><ul><li>Again, we are using curl command to download the containerd.service file from the containerd GitHub repository (https://raw.githubusercontent.com/containerd/containerd/main/).</li><li>The containerd.service file is needed to manage containerd as a systemd service, allowing it to start automatically and manage its lifecycle.</li></ul><p><strong>4. Move systemd service file to appropriate directory:</strong></p><pre>sudo mkdir -p /usr/local/lib/systemd/system/<br>sudo mv containerd.service /usr/local/lib/systemd/system/</pre><ul><li>These commands create a directory (mkdir -p /usr/local/lib/systemd/system/) if it doesn&#39;t exist (-p flag), then move (mv) the containerd.service file to that directory.</li><li>Placing containerd.service in /usr/local/lib/systemd/system/ ensures that systemd can locate and manage the containerd service effectively.</li></ul><p><strong>5. Configure containerd with default settings:</strong></p><pre>sudo mkdir -p /etc/containerd/<br>sudo containerd config default | sudo tee /etc/containerd/config.toml &gt; /dev/null</pre><ul><li>These commands create a directory (mkdir -p /etc/containerd/) if it doesn&#39;t exist, then generate the default configuration for containerd (containerd config default). The output (|) of this configuration command is redirected (tee) to /etc/containerd/config.toml. The tee command also outputs to /dev/null to discard unnecessary console output.</li><li>This step ensures that containerd has a basic configuration file (config.toml) in place with default settings, which is necessary for its proper operation.</li></ul><p><strong>6. Modify containerd configuration file to enable systemd cgroup integration:</strong></p><pre>sudo sed -i &#39;s/SystemdCgroup \= false/SystemdCgroup \= true/g&#39; /etc/containerd/config.toml</pre><ul><li>This command uses sed (stream editor) to replace (s) occurrences of SystemdCgroup = false with SystemdCgroup = true in the /etc/containerd/config.toml file.</li><li>Enabling systemd cgroup integration ensures that containerd uses systemd for managing cgroups (control groups), which is the preferred method for managing resource limits and isolation in modern Linux distributions.</li></ul><p><strong>7. Reload systemd manager configuration:</strong></p><pre>sudo systemctl daemon-reload</pre><ul><li>systemctl daemon-reload instructs systemd to reload its configuration files and units.</li><li>After making changes to systemd service files or configurations, you need to reload systemd to apply those changes.</li></ul><p><strong>8. Enable and start containerd service:</strong></p><pre>sudo systemctl enable --now containerd</pre><ul><li>systemctl enable --now containerd enables (enable) the containerd service to start on boot (--nowalso starts it immediately).</li><li>Enabling the service ensures that containerd starts automatically when the system boots up (enable), and starting it immediately (--now) ensures that it is running without requiring a manual start.</li></ul><p><strong>9. Check status of containerd service:</strong></p><pre>systemctl status containerd</pre><ul><li>systemctl status containerd displays the current status of the containerd service.</li><li>This command is used to verify that containerd has started successfully and is running without any errors. Here is my output:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EetxyzPh3z_j3nJ0_Dg5xQ.png" /></figure><h4>Now we need to install Runc</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UJdBNAxc3wp5zN0vf-6VPQ.png" /></figure><p>runc is a command-line tool for spawning and running containers according to the Open Container Initiative (OCI) specification. It is the industry-standard runtime used by container engines like <strong>Docker</strong>, <strong>containerd</strong>, and others to execute containers based on OCI-compliant container images.</p><p>You can find the latest release here: <a href="https://github.com/opencontainers/runc/releases/">https://github.com/opencontainers/runc/releases/</a></p><p>Execute these commands on all 3 instances.</p><p>Here curl downloads run runtime into the home directory:</p><pre>curl -LO https://github.com/opencontainers/runc/releases/download/v1.1.13/runc.amd64</pre><p>This ensures that runc, a container runtime executable for the amd64 architecture, is properly installed and executable on the system:</p><pre>sudo install -m 755 runc.amd64 /usr/local/sbin/runc</pre><h4>Install CNI plugins (<a href="https://www.cni.dev/">https://www.cni.dev</a>)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*zHNsCEb0KWkvq7JogWNQ_Q.png" /></figure><p>CNI (Container Network Interface) plugins are a set of specifications and plugins that define how network connectivity is established and managed for containers running on Linux-based systems.</p><p>CNI plugins provide a standardized way for container orchestrators (like Kubernetes, Docker, etc.) to configure networking for containers. They handle tasks such as assigning IP addresses, creating virtual network interfaces, setting up routing rules, and managing network policies.</p><p>You can find the latest versions here:<br><a href="https://github.com/containernetworking/plugins/releases">https://github.com/containernetworking/plugins/releases</a></p><p>Go ahead and run these commands on all 3 instances. These commands download and install the plugins within the instances.</p><pre>curl -LO https://github.com/containernetworking/plugins/releases/download/v1.5.1/cni-plugins-linux-amd64-v1.5.1.tgz<br>sudo mkdir -p /opt/cni/bin<br>sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.5.1.tgz</pre><h3>Installing Kubernetes (kubeadm, kubelet and kubectl)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wocyH-1g-ITCnsRleZYVgw.png" /></figure><p>Kubernetes, also known as K8s, is an open source system for automating deployment, scaling, and management of containerized applications.</p><h3>kubeadm</h3><p>kubeadm is a command-line tool used for bootstrapping Kubernetes clusters. It facilitates the setup of a basic Kubernetes cluster by handling the initialization of the control plane, joining nodes to the cluster, and ensuring that the cluster meets the minimum requirements for Kubernetes operation.</p><p>System administrators and DevOps engineers use kubeadm during initial cluster setup, upgrades, and node management. It abstracts complex Kubernetes setup tasks into simpler commands.</p><h3>kubelet</h3><p>kubelet is an essential Kubernetes component running on each node in the cluster. It&#39;s responsible for managing the containers on the node, ensuring they run in the desired state specified by the Kubernetes manifests.</p><p>kubelet is critical for the operational health of each node in a Kubernetes cluster. It ensures that applications defined in Pods are correctly scheduled, launched, and maintained on the node.</p><h3>kubectl</h3><p>kubectl is the command-line tool used for interacting with the Kubernetes cluster. It allows users to deploy and manage applications, inspect and manage cluster resources, and view logs and metrics.</p><p>Developers, system administrators, and operators use kubectl extensively to interact with Kubernetes clusters. It provides a powerful interface for managing and troubleshooting applications and resources in Kubernetes.</p><p>Together, kubeadm, kubelet, and kubectl form the core toolset for deploying, managing, and operating Kubernetes clusters, catering to different aspects of cluster lifecycle management and application deployment in Kubernetes environments.</p><p>Run these commands on every instance:</p><pre># Update the local package database on your Linux system<br>sudo apt-get update<br><br># Install necessary packages required for securely downloading packages over HTTPS<br>sudo apt-get install -y apt-transport-https ca-certificates curl gpg<br><br># Download and install the Kubernetes package repository signing key<br>curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg<br><br># Add the Kubernetes package repository to your system&#39;s package sources<br>echo &#39;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /&#39; | sudo tee /etc/apt/sources.list.d/kubernetes.list<br><br># Update the local package database again to include the newly added Kubernetes repository<br>sudo apt-get update<br><br># Install Kubernetes components (kubelet, kubeadm, kubectl) on your system<br>sudo apt-get install -y kubelet kubeadm kubectl<br><br># Prevent apt from automatically updating the specified packages<br>sudo apt-mark hold kubelet kubeadm kubectl</pre><p>And now verify that the installation is a success by running these commands:</p><pre># Displays the version of kubeadm installed on your system<br>kubeadm version<br><br># Displays the version of kubelet installed on your system<br>kubelet --version<br><br># Displays the client version of kubectl installed on your system.<br>kubectl version --client</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OxeqOdHsdRBNpalG3O51mQ.png" /></figure><h3>Now configure crictl to work with containerd</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/823/1*GNtCkGLEiOl8CT7_O9FnlQ.png" /></figure><p>Configuring crictl to work with containerd involves specifying the runtime endpoint where containerd listens for container runtime requests. Let&#39;s break down why this configuration step is necessary and what it entails:</p><p>crictl is a command-line interface (CLI) tool for interacting with container runtimes that adhere to the Container Runtime Interface (CRI) specification.</p><p>It allows administrators and developers to manage containers and pods directly, inspect container runtime configuration, and perform troubleshooting tasks.</p><p>containerd communicates with tools like crictl over a Unix socket (unix:///var/run/containerd/containerd.sock).</p><p>This socket acts as a communication channel through which crictl sends commands to containerd and receives responses.</p><p>By configuring crictl with the runtime-endpoint option (sudo crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock), you specify where crictl should send its commands related to container management.</p><p>This step ensures that crictl interacts with containerd correctly and can perform operations such as creating, inspecting, starting, stopping, and deleting containers managed by containerd.</p><p>Kubernetes uses crictl (via cri-containerd) as an interface to manage containers on nodes that run containerd.</p><p>Configuring crictl to point to containerd&#39;s Unix socket ensures that Kubernetes can orchestrate containers using containerd as the underlying runtime without issues.</p><p>This configuration step is essential for maintaining operational continuity and ensuring that container operations are managed correctly within Kubernetes clusters using containerd as the runtime engine.</p><p>Run this on every instance:</p><pre>sudo crictl config runtime-endpoint unix:///var/run/containerd/containerd.socSe the controlplane node</pre><h3>Setting up the control-plane node</h3><p>These commands should only be run on kubemaster. Kubemaster will control our mules and schedule to run the containers there.</p><p>The following command Initializes a new Kubernetes control plane. The <strong>apiserver-advertise-address</strong> parameter should be our Kubemaster static IP.</p><pre>sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.64.100</pre><p>When complete you should get the following output, which contains the kubeadm commands that you need to save to run on mule nodes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*np7uaamTXv_dABJf9I3u6w.png" /></figure><p>When we run sudo kubeadm init, Kubernetes performs several crucial steps to set up the control plane:</p><ul><li>It generates the necessary TLS certificates needed for secure communication within the cluster.</li><li>It starts essential components like the API Server, Controller Manager, and Scheduler.</li><li>It generates a <strong>kubeconfig</strong> file for the kubectl command-line tool, which allows administrative access to the cluster.</li><li>It generates a token that other nodes can use to join the cluster.</li></ul><h4>Post-Initialization Steps:</h4><p>After running sudo kubeadm init, Kubernetes provides instructions and commands that you should run on worker nodes to join them to the cluster. These commands typically include using the kubeadm join command with a token and discovery token hash generated during initialization. Here is my output:</p><pre>Your Kubernetes control-plane has initialized successfully!<br><br>To start using your cluster, you need to run the following as a regular user:<br><br>  mkdir -p $HOME/.kube<br>  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config<br>  sudo chown $(id -u):$(id -g) $HOME/.kube/config<br><br>Alternatively, if you are the root user, you can run:<br><br>  export KUBECONFIG=/etc/kubernetes/admin.conf<br><br>You should now deploy a pod network to the cluster.<br>Run &quot;kubectl apply -f [podnetwork].yaml&quot; with one of the options listed at:<br>  https://kubernetes.io/docs/concepts/cluster-administration/addons/<br><br>Then you can join any number of worker nodes by running the following on each as root:<br><br>kubeadm join 192.168.64.100:6443 --token 6h6iro.dvvn76jr20pn9i61 \<br> --discovery-token-ca-cert-hash sha256:17b8ad18d02f4c6bb5d6705273aafdf9460840dd88a53271192c001e96425d7e </pre><h4>Configuring kubectl</h4><p>kubectl is a command-line tool for interacting with Kubernetes clusters. This command is part of setting up kubectl to interact with the Kubernetes cluster that was initialized using sudo kubeadm init.</p><p>Once configured, kubectl commands can be executed directly by the user without needing to specify the configuration file location each time.</p><p>Run these commands on the kubemaster:</p><pre># Creates the .kube directory in the user&#39;s home directory<br>mkdir -p $HOME/.kube<br><br># Copies the Kubernetes cluster configuration file (admin.conf) to the .kube/config file in the user&#39;s home directory.<br>sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config<br><br># Changes the ownership of the config file in .kube directory to the current user.<br>sudo chown $(id -u):$(id -g) $HOME/.kube/config</pre><p>Now lets verify that cluster is reached via kubectl, execute on kubemaster:</p><pre>kubectl -n kube-system get pods</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yctC9UqLNVwkMDxcxxKaKA.png" /></figure><h4><strong>Install Weave Net</strong></h4><p>Next we need to make sure our Pods can communicate with each other, which is why we must deploy a Container Network Interface (CNI) based Pod network add-on. We’ll use <strong>kubectl</strong> to initiate the service.</p><p>Execute the following command on kubemaster:</p><pre>kubectl apply -f https://reweave.azurewebsites.net/k8s/v1.28/net.yaml</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/896/1*mIROrkgBExJjHuUp0ZsZJA.png" /></figure><p>By now, the control plane node should be operational, with all pods in the <strong>kube-system </strong>namespace. Please verify this to ensure the control plane’s functionality and health. Run:</p><pre>kubectl -n kube-system get pods</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YD87tVwUDuTlDBMRZMBPag.png" /></figure><h4>Time to join the mules into the cluster</h4><p>Connect to each mule and execute the entire kubeadm join command that was copied earlier from the output of the kubeadm init command.</p><p>This step integrates each mule into the Kubernetes cluster&#39;s control plane, allowing them to join and contribute to cluster operations.</p><p>It guarantees that all nodes are synchronized and capable of participating in workload distribution and management tasks across the Kubernetes cluster.</p><p>This process is essential for achieving a functional and scalable Kubernetes environment where nodes collaborate seamlessly to run containerized applications.</p><pre>sudo kubeadm join 192.168.64.100:6443 --token 6h6iro.dvvn76jr20pn9i61 \<br> --discovery-token-ca-cert-hash sha256:17b8ad18d02f4c6bb5d6705273aafdf9460840dd88a53271192c001e96425d7e</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dDxUHwhOrvztk4Dwq-ll6g.png" /></figure><p>Also, you can always get a new join command from control-pane instance by running this in the kubemaster, which will generate a new join token:</p><pre>kubeadm token create --print-join-command</pre><p>Now check that all the mules joined the cluster by running this command in the kubemaster:</p><pre>kubectl get nodes</pre><p>You should get this output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*FlyQAAIvjrsdBnOBccz1sg.png" /></figure><h4>Validating the Kubernetes setup</h4><p>To ensure the Kubernetes setup functions correctly, verify by deploying an nginx pod within the cluster.</p><p>Execute the following commands on the Kubernetes master node:</p><pre>kubectl run test-nginx --image=nginx</pre><p>then run this command to check the status of the service:</p><pre>kubectl get pod test-nginx</pre><p>At first you will see the following output where the READY status is 0/1 but then after a few seconds you should get READY 1/1 just like I have it in the following output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*ghnlnMQZrK5wlvgrrvj0Xw.png" /></figure><p>Congratulations! You have setup Kubernetes!!!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/381/1*eibSqXYDFcULAAOKBwROqg.png" /></figure><p>To stop the nginx pod that you deployed using kubectl run, you can delete the pod using kubectl delete pod. Here&#39;s how you can do it:</p><pre>kubectl delete pod test-nginx</pre><p>Kubernetes manages resources like pods, and deleting a pod stops the associated container(s) and removes the pod from the cluster.</p><p>And finally, the following diagram describes perfectly our current setup.</p><p>Enjoy it and Happy Kuberneting!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1004/1*NG9EtYIKdECQPn0i0srEug.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4645f8f30c45" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/setting-up-kubernetes-cluster-with-multipass-on-a-mac-a-step-by-step-guide-4645f8f30c45">Setting up Kubernetes Cluster with Multipass on A Mac — A Step by Step Guide</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekend Docker Build Makeover: Tips and Tricks]]></title>
            <link>https://levelup.gitconnected.com/weekend-docker-build-makeover-tips-and-tricks-18dee11abb2a?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/18dee11abb2a</guid>
            <category><![CDATA[servers]]></category>
            <category><![CDATA[docker-image]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[productivity-hacks]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Sun, 07 Jul 2024 17:09:37 GMT</pubDate>
            <atom:updated>2024-07-07T17:09:37.440Z</atom:updated>
            <content:encoded><![CDATA[<p>If you love Docker then you might be sharing one of the biggest pains when it comes to running your builds from the console. The output by default lacks coloring and its hard to tell whats going on by looking at a lot of repetitive text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/825/1*iWhkFOSBWPwFMX5Viswehw.png" /></figure><p>I’ve dedicated a few hours to enhancing the docker image build console output by adding color to various text fragments, and the result is fantastic. I am really excited to share it with you.</p><p>First things first, I whipped up a multi-stage Dockerfile for a fun little NodeJS project. I used NCC to bundle my whole NodeJS app and its modules into one slick .JS file, making my final Docker image way smaller. With NCC, I shrank it from a whopping 1GB to just 133.99MB!</p><p>Here is the file and a gist link, I’ve explained every bit of it in the code itself but here is a line by line explanation of it.<br><a href="https://gist.github.com/jsmuster/70082c79d95d663a872d14a67166ff11">https://gist.github.com/jsmuster/70082c79d95d663a872d14a67166ff11</a></p><h3>Stage 1: Builder</h3><p>This is the part which creates a temporary Docker image used to compile our NodeJS application code into one single Javascript file, which is used in the next step of our multi-stage build.<br> <strong><br>Base Image</strong></p><pre>FROM node:lts-alpine as builder</pre><ul><li>Uses the latest long-term support (LTS) version of Node.js with an Alpine Linux base image for the builder stage. Alpine is chosen for its small size and efficiency.</li></ul><p><strong>Environment Variable</strong></p><pre>ENV NODE_ENV=production</pre><ul><li>Sets the NODE_ENV environment variable to production, indicating that the application is in production mode.</li></ul><p><strong>Working Directory</strong></p><pre>WORKDIR /usr/src/app</pre><ul><li>Sets the working directory inside the container to /usr/src/app</li></ul><p><strong>Copy Package Files</strong></p><pre>COPY [&quot;package.json&quot;, &quot;package-lock.json*&quot;, &quot;npm-shrinkwrap.json*&quot;, &quot;./&quot;]</pre><ul><li>Copies package.json, package-lock.json, and npm-shrinkwrap.json (if they exist) to the working directory. These files are used to install the necessary dependencies.</li></ul><p><strong>Install Dependencies</strong></p><pre>RUN npm install --production</pre><ul><li>Installs the production dependencies listed in the prior step.</li></ul><p><strong>Install NCC</strong></p><pre>RUN npm install -g @zeit/ncc</pre><ul><li>Globally installs ncc (Node.js Compiler Collection), used to compile the Node.js project into a single file.</li></ul><p><strong>Copy Source Code</strong></p><pre>COPY . .</pre><ul><li>Copies the rest of the application source code to the working directory.</li></ul><p><strong>Build Project</strong></p><pre>RUN export NODE_OPTIONS=--openssl-legacy-provider &amp;&amp; ncc build ./bin/www -o dist</pre><ul><li>Sets NODE_OPTIONS to use the OpenSSL legacy provider and runs ncc to compile the project located at ./bin/www into a single file output in the dist directory.</li></ul><p><strong>Remove Node Modules</strong></p><pre>RUN rm -rf node_modules</pre><ul><li>Removes the node_modules directory to save space since it is no longer needed after the project is build.</li></ul><p><strong>Expose Port</strong></p><pre>EXPOSE 3000</pre><ul><li>Informs Docker that the container listens on port 3000.</li></ul><h3><strong>Stage 2: Build the actual Docker image</strong></h3><p>This is the part that builds the actual image</p><p><strong>Base Image</strong></p><pre>FROM node:lts-alpine as backend</pre><ul><li>Uses the same Node.js LTS Alpine image for our NodeJS application.</li></ul><p><strong>Environment Variable</strong></p><pre>ENV NODE_ENV=production</pre><ul><li>Sets the NODE_ENV environment variable to production.</li></ul><p><strong>Working Directory</strong></p><pre>WORKDIR /usr/src/app</pre><ul><li>Sets the working directory inside the container to /usr/src/app. You could change this to anything you like.</li></ul><p><strong>Copy Compiled Files</strong></p><pre>COPY --from=builder /usr/src/app/dist .</pre><ul><li>Copies the compiled files from the dist directory of the builder docker image to the working directory of the current docker image.</li></ul><p><strong>Define Command</strong></p><pre>CMD [&quot;node&quot;, &quot;index.js&quot;]</pre><ul><li>Sets the default command to run the application using node index.js.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uvVVjKQ31umFF_-1FP2jrw.png" /></figure><p>Now here is the actual script I wrote to enhance the Docker build output.</p><p>Because trying to read a detailed Docker build log without any color is like watching a mime perform in the dark — you know something is happening, but you have no idea what.</p><p>The process began with an attempt to color the initial dash and number pattern “#1”. Once this step was successful, I was able to proceed and convert the entire output accordingly. Here is a small snippet of the output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/494/1*gDDPE4JQN10V-_hnwTyvbQ.png" /></figure><p>I’ve shared the script on Github gists, so go ahead and use it as boiler plate and enhance it even further. Lets break this code down line by line:</p><p><a href="https://gist.github.com/jsmuster/fcce009ddb35fa15f2f409b20c4c94f2">https://gist.github.com/jsmuster/fcce009ddb35fa15f2f409b20c4c94f2</a></p><p><strong>Shebang</strong></p><pre>#!/bin/sh</pre><ul><li>This specifies that the script should be run using the sh shell. This is a part of every shell script by default, just make sure to have this at the top of the file, otherwise your scripts won’t execute.</li></ul><p><strong>ANSI Color Codes</strong></p><pre># Regular text colors<br>BLACK=&#39;\033[0;30m&#39;<br>RED=&#39;\033[0;31m&#39;<br>GREEN=&#39;\033[0;32m&#39;<br>YELLOW=&#39;\033[0;33m&#39;<br>BLUE=&#39;\033[0;34m&#39;<br>MAGENTA=&#39;\033[0;35m&#39;<br>CYAN=&#39;\033[0;36m&#39;<br>WHITE=&#39;\033[0;37m&#39;<br><br># Bold text colors<br>BOLD_BLACK=&#39;\033[1;30m&#39;<br>BOLD_RED=&#39;\033[1;31m&#39;<br>BOLD_GREEN=&#39;\033[1;32m&#39;<br>BOLD_YELLOW=&#39;\033[1;33m&#39;<br>BOLD_BLUE=&#39;\033[1;34m&#39;<br>BOLD_MAGENTA=&#39;\033[1;35m&#39;<br>BOLD_CYAN=&#39;\033[1;36m&#39;<br>BOLD_WHITE=&#39;\033[1;37m&#39;<br><br># Background colors<br>BG_BLACK=&#39;\033[40m&#39;<br>BG_RED=&#39;\033[41m&#39;<br>BG_GREEN=&#39;\033[42m&#39;<br>BG_YELLOW=&#39;\033[43m&#39;<br>BG_BLUE=&#39;\033[44m&#39;<br>BG_MAGENTA=&#39;\033[45m&#39;<br>BG_CYAN=&#39;\033[46m&#39;<br>BG_WHITE=&#39;\033[47m&#39;<br><br>NC=&#39;\033[0m&#39; # No Color</pre><ul><li>Defines various ANSI color codes for regular text, bold text, and background colors. We’re going to use these to color output in the console.</li></ul><p><strong>Colored Echo Functions</strong></p><pre>echo_red() {<br>    echo &quot;${RED}$1${NC}&quot;<br>}<br><br>echo_green() {<br>    echo &quot;${GREEN}$1${NC}&quot;<br>}<br><br>echo_yellow() {<br>    echo &quot;${YELLOW}$1${NC}&quot;<br>}<br><br>echo_blue() {<br>    echo &quot;${BLUE}$1${NC}&quot;<br>}</pre><ul><li>Defines functions to print text in specific colors (red, green, yellow, and blue).</li></ul><p><strong>Colorize Output Function</strong></p><pre>colorize_output() {<br>    while IFS= read -r line; do<br>        # Check for the pattern &quot;#[0-9]* CACHED&quot; and colorize it<br>        if echo &quot;$line&quot; | grep -q &quot;#[0-9]*&quot;; then<br>            # Apply color to the matched pattern<br>            line=$(color_pattern &quot;$line&quot;)<br>        fi<br>        echo &quot;$line&quot;<br>    done<br>}</pre><ul><li>Reads lines from the input and checks for patterns to colorize using the color_pattern function. The IFS= read -r line loop reads lines without trimming whitespace.</li></ul><p><strong>Color Pattern Function</strong></p><pre>color_pattern() {<br><br>    local input=&quot;$1&quot;<br>    local red=&#39;\\033[0;31m&#39;<br><br>    local green=&#39;\\033[0;32m&#39;<br>    local yellow=&#39;\\033[0;33m&#39;<br>    local blue=&#39;\\033[0;34m&#39;<br><br>    local black=&#39;\\033[0;30m&#39;<br>    local magenta=&#39;\\033[0;35m&#39;<br>    local cyan=&#39;\\033[0;36m&#39;<br>    local white=&#39;\\033[0;37m&#39;<br><br>    # Bold text colors<br>    local bold_black=&#39;\\033[1;30m&#39;<br>    local bold_red=&#39;\\033[1;31m&#39;<br>    local bold_green=&#39;\\033[1;32m&#39;<br>    local bold_yellow=&#39;\\033[1;33m&#39;<br>    local bold_blue=&#39;\\033[1;34m&#39;<br>    local bold_magenta=&#39;\\033[1;35m&#39;<br>    local bold_cyan=&#39;\\033[1;36m&#39;<br>    local bold_white=&#39;\\033[1;37m&#39;<br><br>    # Background colors<br>    local bg_black=&#39;\\033[40m&#39;<br>    local bg_red=&#39;\\033[41m&#39;<br>    local bg_green=&#39;\\033[42m&#39;<br>    local bg_yellow=&#39;\\033[43m&#39;<br>    local bg_blue=&#39;\\033[44m&#39;<br>    local bg_magenta=&#39;\\033[45m&#39;<br>    local bg_cyan=&#39;\\033[46m&#39;<br>    local bg_white=&#39;\\033[47m&#39;<br><br>    local reset=&#39;\\033[0m&#39;<br>    local pattern=&quot;#[0-9]+&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${bold_white}${bg_black}\1${reset}/g&quot;)<br><br>    pattern=&quot;DONE&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${green}\1${reset}/g&quot;)<br><br>    pattern=&quot;exporting&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${green}\1${reset}/g&quot;)<br><br>    pattern=&quot;writing image&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${bold_black}\1${reset}/g&quot;)<br><br>    pattern=&quot;[0-9]+\.[0-9]+s&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${blue}\1${reset}/g&quot;)<br><br>    pattern=&quot;CACHED&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${yellow}\1${reset}/g&quot;)<br><br>    pattern=&quot;\[internal\]&quot;<br>    <br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/($pattern)/${cyan}\1${reset}/g&quot;)<br><br>    pattern=&#39;\[builder [0-9]+/[0-9]+\]&#39;<br><br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/(\[builder [0-9]+\/[0-9]+\])/${bold_green}\1${reset}/g&quot;)<br><br>    pattern=&#39;\[backend [0-9]+/[0-9]+\]&#39;<br><br>    input=$(echo &quot;$input&quot; | sed -E &quot;s/(\[backend [0-9]+\/[0-9]+\])/${magenta}\1${reset}/g&quot;)<br>    <br>    # Return the modified string<br>    echo &quot;$input&quot;<br>}</pre><ul><li>This function holds local color variables because it needs to escape the strings, it applies various color codes to different patterns in the input string using sed. SED is a stream editor in Linux.</li></ul><p><strong>Initial Status Message</strong></p><pre>echo_green &quot;Starting the build script...&quot;</pre><ul><li>Prints a message indicating the start of the build script in green.</li></ul><p><strong>Run Docker Build Function</strong></p><pre>run_docker_build() {<br>    docker image build --progress=plain -t cybernetically-web-backend:latest . 2&gt;&amp;1 | tee dockerbuild.log | colorize_output<br>}</pre><ul><li>Defines a function to run the Docker build command and pipe its output to both a log file and the colorize_output function. This is the line that runs the docker build, you want to replace the <strong>“cybernetically-web-backend:latest”</strong> name of the image to something of your own. This will also output your build log into dockerbuild.log</li></ul><p><strong>Execute Docker Build</strong></p><pre>run_docker_build</pre><ul><li>Calls the run_docker_build function to start the Docker build process with colorized output.</li></ul><p><strong>Final Status Message</strong></p><pre>echo_green &quot;build script finished.&quot;</pre><ul><li>Prints a message indicating the completion of the build script in green.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GkfH6llJOrk3hXg5BvaiXg.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=18dee11abb2a" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/weekend-docker-build-makeover-tips-and-tricks-18dee11abb2a">Weekend Docker Build Makeover: Tips and Tricks</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Re-create the RxJS Library from Scratch (Part 2): Deep Dive into RxJS Operators]]></title>
            <link>https://levelup.gitconnected.com/re-create-the-rxjs-library-from-scratch-part-2-deep-dive-into-rxjs-operators-bdc32dc44e53?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/bdc32dc44e53</guid>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[reactive-programming]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Tue, 04 Apr 2023 17:20:10 GMT</pubDate>
            <atom:updated>2023-05-01T03:16:49.413Z</atom:updated>
            <content:encoded><![CDATA[<p>In the previous article, we delved into the fundamentals of Observables by creating a custom RxJS library from scratch. While we were able to get the basic functionality up and running, there is another aspect of Observables that we’ve yet to explore: <strong>operators</strong>. In this article, we will continue our journey of learning about Observables by implementing RxJS Operators in our custom library.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Y35KHz0ik8bv8ZrU.jpg" /></figure><p><strong><em>The previous article:</em></strong></p><p><a href="https://levelup.gitconnected.com/re-create-the-rxjs-library-from-scratch-deep-dive-into-rxjs-observables-cb9a3c000e0">Re-create the RxJS Library from Scratch: Deep Dive into RxJS Observables</a></p><p>There are two types of operators in RxJS.</p><h4><strong>Creation Operators</strong></h4><p>These are standalone functions that create the <strong>Observable</strong>. For instance, we already implemented <strong>of</strong>, <strong>interval</strong> &amp; <strong>range</strong> in our library. These methods create an Observable and return it for further use by <strong>Pipeable Operators</strong>.</p><p>Any process that generates or transforms data could be made into the Creation Operator.</p><p>Every <strong>Creation Operator</strong> follows the following model:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/1*Q3l2EwYUovBeYn-36CU0hg.png" /></figure><p><em>For example:</em></p><p>The <strong>“of”</strong> operator accepts a set of values and propagates them into the operator with a <strong>forEach </strong>loop</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z_PGfIyj5zN-q64AWABOjQ.png" /></figure><p><strong>“interval”</strong> operator utilizes the <em>setInterval</em> method to propagate an incremented number at a set interval.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_0xTFjqylsV7zovKenmX2g.png" /></figure><p><strong>“range”</strong> operator in RxJS allows for the propagation of a sequence of values within a defined range</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_UQSrsIKoa16uyv_n3PDRg.png" /></figure><h4>Pipeable Operators</h4><p>These are operator functions that <em>filter</em> or <em>transform</em> a value. In practice they are chained together and for that reason they are configured through the <strong>pipe</strong> method, which is part of the <strong>Observable</strong> returned from a <strong>Creation Operator</strong>.</p><p>This is the interaction model used in the <strong><em>RxJS</em></strong> library, demonstrating how a value is propagated into a subscription.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*39pKwbcd4VbC52ZyT_E48A.png" /></figure><p><em>Here is an example:<br></em>The first pipe <strong><em>filters</em></strong> the values by selecting only those that are odd (i.e., not divisible by 2). The second pipe modifies the <strong><em>filtered</em></strong> <strong><em>values</em></strong> by adding 10 to each. As a result, the sequence of the initial values being piped through the two pipes is [3, 5, 11, 13, 23].</p><pre>of(3, 5, 8, 11, 13, 18, 23).pipe(<br>    filter(n =&gt; n % 2 === 1),<br>    map(n =&gt; n + 10)<br>  )<br>  .subscribe(result =&gt; console.log(result));</pre><p>The console output is the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*dI83w5948ktBHh0-87ml2A.png" /></figure><p>In order to propagate a value through a series of pipes within our custom rxjs library, we could use a reducer, which is what RxJS library uses, see my article on mastering the reducers here:</p><p><a href="https://medium.com/@jsmuster/mastering-reducers-a-comprehensive-guide-for-everyone-298c23ad21c7">https://medium.com/@jsmuster/mastering-reducers-a-comprehensive-guide-for-everyone-298c23ad21c7</a></p><p>But we will employ a basic for loop and an iterator pattern to pass values through our pipes. In the iterator pattern, each transformation returns an object containing “<strong>done</strong>” and “<strong>value</strong>” properties. The <strong><em>done</em></strong> property signals when to stop the transformation from proceeding further.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*rfQg2gOKfzippeYweR3gOg.png" /></figure><pre>for(const pipe of pipes)<br>{<br>  result = pipe(val);<br><br>  if(result.done == true)<br>  {<br>    break;<br>  }<br>  else<br>  {<br>    val = result.value;<br>  }<br><br>  count++;<br>};</pre><p>Each operator must return a function that takes (val, index) as parameters and returns an object, following the Iterator model, with value and done properties. The done property indicates whether the value should continue to propagate within the operator chain.</p><p>Here is the ‘<strong><em>filter</em></strong>’ operator, which accepts a predicate function as its argument. This function is used to decide whether the value should continue to propagate through the pipable chain or not, based on the result of the predicate function.</p><p><em>In programming, a predicate is a function that takes one or more arguments and returns a boolean value, either </em><em>true or </em><em>false. Predicates are commonly used in functions like filtering or searching. They are called &quot;predicates&quot; because they essentially make a statement about the input that is either true or false, allowing the program to decide whether to include or exclude the input based on result of the predicate function.</em></p><pre>rxjs.operators.filter = (predicate, thisArg) =&gt; {<br>  <br>  let ret;<br>  let efnfilter = (val, index) =&gt; {<br><br>    ret = predicate(val, index);<br><br>    if(ret === true)<br>    {<br>      return {value: val, done: false};<br>    }<br>    else<br>    {<br>      return {done: true};<br>    }<br>  };<br><br>  if(thisArg != null)<br>  {<br>    return efnfilter.bind(thisArg);<br>  }<br>  else<br>  {<br>    return efnfilter;<br>  }<br>};</pre><p>This is the ‘<strong>map</strong>’ operator, which executes for each value produced and transforms the value.</p><p>Both <strong>filter</strong> and <strong>map</strong> accept ‘<strong><em>thisArg</em></strong>’ as a parameter which gets applied as “<strong>this</strong>” of that operand.</p><pre>rxjs.operators.map = (transformer, thisArg) =&gt; {<br>  <br>  let ret;<br>  let efnmap = (val, index) =&gt; {<br>    <br>    ret = transformer(val, index);<br>    <br>    return {value: ret, done: false};<br>  };<br>  <br>  if(thisArg != null)<br>  {<br>    return efnmap.bind(thisArg);<br>  }<br>  else<br>  {<br>    return efnmap;<br>  }<br>};</pre><p>You’ll find the <strong><em>take</em></strong> operator implementation in the code as well. At this point I implemented 3 pipes and we can successfully run the following example:</p><pre>let rxjs = require(&#39;./Observable.js&#39;);<br>let { of } = rxjs;<br>let { filter, map, take } = rxjs.operators;<br><br>of(3, 5, 8, 11, 13, 18, 23).pipe(<br>    filter(n =&gt; n % 2 === 1),<br>    map(n =&gt; n + 10),<br>    take(3)<br>  )<br>  .subscribe(result =&gt; console.log(result));</pre><p>Here is the <strong>RxJS</strong> library implementation:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ff9ubhopv%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ff9ubhopv%2F&amp;image=https%3A%2F%2Fwww.gravatar.com%2Favatar%2Fb52cb468a317675a5f29869d943d8fb9%3Fs%3D80&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d6604d826fae3e6e3167b8df12b375c/href">https://medium.com/media/5d6604d826fae3e6e3167b8df12b375c/href</a></iframe><p>And here is <strong>our</strong> <strong>custom</strong> <strong>rxjs</strong> <strong>library</strong> implementation:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F1L0xe5tn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F1L0xe5tn%2Fembed%2Fjs&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/b971f1cc2cdc889aea187131ce4b452d/href">https://medium.com/media/b971f1cc2cdc889aea187131ce4b452d/href</a></iframe><p>We get the following output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*amrj5X-zpPqvCYkreF524w.png" /></figure><h4>Conclusion</h4><p>This article has provided a deep dive into the world of RxJS Operators by extending the custom RxJS library we created in the previous article.</p><p>We explored two types of operators, <strong>Creation Operators</strong> and <strong>Pipeable Operators</strong>, and their roles in processing data within an <strong>Observable</strong>. We also demonstrated how to implement these operators, using <strong>filter</strong>, <strong>map</strong>, and <strong>take</strong> as examples.</p><p>By understanding the core concepts and implementations of RxJS Operators, we can better appreciate the power and flexibility that RxJS brings to your JavaScript projects.</p><p>This knowledge will help you build more efficient and readable asynchronous code, ultimately enhancing the overall quality of your applications.</p><h3>Check out my open source framework QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>Check out my other articles</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li></ul><h3>Level Up Coding</h3><p>Thanks for being a part of our community! Before you go:</p><ul><li>📰 View more content in the <a href="https://levelup.gitconnected.com/?utm_source=pub&amp;utm_medium=post">Level Up Coding publication</a></li><li>💰 Free coding interview course ⇒ <a href="https://skilled.dev/?utm_source=luc&amp;utm_medium=article">View Course</a></li><li>🔔 Follow us: <a href="https://twitter.com/gitconnected">Twitter</a> | <a href="https://www.linkedin.com/company/gitconnected">LinkedIn</a> | <a href="https://newsletter.levelup.dev/">Newsletter</a></li></ul><p>🚀👉 <a href="https://jobs.levelup.dev/talent/welcome?referral=true"><strong>Join the Level Up talent collective and find an amazing job</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdc32dc44e53" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/re-create-the-rxjs-library-from-scratch-part-2-deep-dive-into-rxjs-operators-bdc32dc44e53">Re-create the RxJS Library from Scratch (Part 2): Deep Dive into RxJS Operators</a> was originally published in <a href="https://levelup.gitconnected.com/">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Глубокое погружение в RxJS Observables: создание библиотеки RxJS с нуля (Russian)]]></title>
            <link>https://medium.com/@jsmuster/%D0%B3%D0%BB%D1%83%D0%B1%D0%BE%D0%BA%D0%BE%D0%B5-%D0%BF%D0%BE%D0%B3%D1%80%D1%83%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-rxjs-observables-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8-rxjs-%D1%81-%D0%BD%D1%83%D0%BB%D1%8F-russian-ae80f8aac5fa?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/ae80f8aac5fa</guid>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[russian]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[application-development]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Mon, 27 Mar 2023 05:46:55 GMT</pubDate>
            <atom:updated>2023-03-27T05:46:55.166Z</atom:updated>
            <content:encoded><![CDATA[<p>В этой статье я рассмотрю концепцию Observables, создавая небольшую библиотеку с нуля. В ходе этого упражнения мы изучим внутреннее устройство Observables, как их можно создавать, и как они могут использоваться для обработки асинхронных потоков данных.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>Как же мы можем создать Observables с нуля? Давайте посмотрим на документацию RxJS для рецепта, как вы видите, класс Observable расширяет Subscribable, а Subscribable — это интерфейс с методом subscribe, поэтому наш Observable должен иметь метод subscribe, верно?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>Конструктор — еще один важный аспект, в нем есть необязательный параметр, который представляет собой функцию, вызываемую при подписке на Observable.</p><p>Эта функция получает объект-подписчик типа Observer, который может использоваться для передачи новых значений с помощью метода next, сигнализирования об ошибке с помощью метода error, или указания успешного завершения с помощью метода complete.</p><p>На основании вышеуказанной информации Observable должен работать следующим образом:</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><ol><li>Создайте Observable и передайте метод в конструктор, который будет отправлять значения в подписчик Observable.</li><li>Наконец, подпишитесь на Observable, передав метод, который будет получать значения.</li></ol><p>Метод subscribe вызывает функцию-конструктор, переданную в Observable. Это означает, что подписка на Observable — это момент, когда он начинает выполнять свою логику, а не во время создания, как обычно полагают. Метод конструктора сохраняется как ссылка и ожидает, когда будет вызван метод subscribe.</p><p>В моем примере я передаю функцию в конструктор Observable, которая выполняется немедленно при подписке, НО обычно она предоставляется реализацией библиотеки, которая указывает, что будет излучать Observable и когда оно будет это делать. И это часто асинхронно.</p><p>Так, например, в реальном сценарии этот сервис выполнит метод subscribe асинхронно только тогда, когда данные успешно получены из HTTP.</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>Или вот Observable, который будет отправлять значение каждую секунду после подписки на него:</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>Теперь давайте реализуем Observable и, наконец, выполним эти примеры кода.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>Вот пример кода, использующий библиотеку rxjs для выполнения его:<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>А вот моя версия с собственной реализацией Observable:<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>Обе функции работают одинаково. Мы получаем следующий вывод в консоль в обоих примерах:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>Теперь давайте рассмотрим пример, где Observable отправляет значение каждую секунду:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>Мы получаем следующий вывод в консоль:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>С помощью всего 80 строк кода нам удалось достичь базовой функциональности Observable, и все работает отлично. Фантастически!</p><p>Давайте повеселимся и улучшим функциональность! Мы можем создать упрощенную версию библиотеки Observables, которая удовлетворяет большинству наших потребностей, не включая полный пакет RxJS в наши проекты.</p><p>Следующий отрывок является частью документации RxJS. Чтобы это работало, нам нужно добавить метод “of”, как показано в следующем примере из документации RxJS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>Я реализовал оператор “of” в обновленной версии и внес некоторые изменения в то, как методы выполняются в Observable. По сути, я вызываю их через обертывающий метод через “call”, чтобы убедиться, что объект подписчика является “this” в методах next, complete и error. Посмотрите на следующий пример:</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>Вы должны получить следующий вывод в консоли при его запуске:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>На странице RxJS Observable есть еще один пример поведения, который использует метод “interval”. Этот метод возвращает объект подписки, который отписывается через 2,5 секунды с помощью функции setTimeout.</p><p>Для этого необходимо включить оператор interval, который генерирует подписку, от которой мы позже можем отписаться.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>Вот пример работы с использованием стандартной библиотеки RxJS:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>Здесь мы имеем экземпляр нашей собственной библиотеки rxjs в действии, как показано в этом примере:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>Удивительно, что оба примера будут производить вывод — это демонстрирует, насколько расширилась наша собственная библиотека rxjs. Теперь мы можем использовать оператор interval для отправки чисел через Observable и отписываться при необходимости.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>В заключение, создание собственной библиотеки Observable с нуля — отличное упражнение, чтобы понять внутреннее устройство Observables и то, как они обрабатывают асинхронные потоки данных. С помощью всего нескольких строк кода мы смогли достичь базовой функциональности Observable и улучшить ее, чтобы она удовлетворяла большинству потребностей.</p><p>Красота Observables заключается в их гибкости и простоте использования. Они могут использоваться для обработки потоков данных в различных сценариях, от простых эмиссий данных до сложных сетевых запросов. Понимая, как работают Observables, мы можем открыть для себя целый новый уровень функциональности в наших приложениях.</p><p>Спасибо за чтение, и я надеюсь, что этот статья дала вам лучшее понимание Observables и того, как создать собственную библиотеку Observable.</p><h3>Проверьте мой фреймворк с открытым исходным кодом QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>Проверьте мои другие статьи.</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>Пожалуйста, поставьте этой статье 👏 и поделитесь ею!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ae80f8aac5fa" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Um mergulho profundo nos Observables do RxJS: recriando a biblioteca RxJS do zero (Portuguese)]]></title>
            <link>https://medium.com/@jsmuster/um-mergulho-profundo-nos-observables-do-rxjs-recriando-a-biblioteca-rxjs-do-zero-portuguese-c40262983556?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/c40262983556</guid>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[application-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[português]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Sun, 26 Mar 2023 05:36:55 GMT</pubDate>
            <atom:updated>2023-03-26T05:36:55.833Z</atom:updated>
            <content:encoded><![CDATA[<p>Neste artigo, vou explorar o conceito de Observables criando uma pequena biblioteca do zero. Através desse exercício, vamos nos aprofundar no funcionamento interno dos Observables, como eles podem ser criados e como podem ser usados para lidar com fluxos de dados assíncronos.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>Então, como fazemos Observables do zero? Vamos dar uma olhada na documentação do RxJS para uma receita, como você pode ver, uma classe Observable estende um Subscribable, e Subscribable é uma interface com o método subscribe, então nosso Observable deve ter um método subscribe, estou certo?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>O construtor é outro aspecto importante, ele tem um parâmetro opcional, que é uma função que é chamada quando o Observable é inscrito.</p><p>Essa função recebe um objeto de assinante do tipo Observer, que pode ser usado para emitir novos valores usando o método next, ou sinalizar um erro usando o método error, ou indicar a conclusão bem-sucedida usando o método complete.</p><p>Com base nas informações acima, o Observable deve funcionar assim:</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><ol><li>Crie o Observable e passe um método para o construtor que irá despachar os valores para o assinante do Observable.</li><li>Finalmente, inscreva-se no Observable passando um método que receberá os valores.</li></ol><p>O método subscribe invoca a função construtora passada para o Observable. Isso significa que a inscrição em um Observable é o ponto em que ele começa a executar sua lógica, em vez de durante a criação, como é comumente acreditado. O método construtor é salvo como uma referência e aguarda o método de inscrição para executá-lo.</p><p>No meu exemplo, estou passando uma função para o construtor do Observable, que é executada imediatamente quando nos inscrevemos, MAS geralmente é fornecida por uma implementação de biblioteca que especifica o que o Observable emitirá e quando o emitirá. E muitas vezes é assíncrono.</p><p>Por exemplo, no cenário real, o seguinte serviço executará o método de inscrição de forma assíncrona, somente quando os dados forem recebidos de um serviço HTTP com sucesso.</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>ou aqui está um Observable que emitirá um valor a cada segundo depois que nos inscrevermos nele:</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>Agora, vamos implementar o Observable e finalmente executar esses exemplos de código.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>Aqui está o código de amostra usando a biblioteca rxjs para executá-lo:<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>E aqui está minha versão com implementação personalizada do Observable:<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>Ambos funcionam da mesma maneira. Obtemos a seguinte saída de console em ambos os exemplos:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>Agora, vamos dar uma olhada no exemplo em que o Observable está emitindo um valor a cada segundo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>Obtemos a seguinte saída de console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>— 19<br>Com apenas 80 linhas de código, conseguimos obter funcionalidades básicas de Observable e tudo parece estar funcionando perfeitamente. Fantástico!</p><p>Vamos nos divertir e melhorar a funcionalidade! Podemos criar uma versão enxuta da biblioteca de Observables que atenda à maioria dos nossos casos de uso, sem precisar incluir o pacote RxJS completo em nossos projetos.</p><p>O trecho a seguir faz parte da documentação do RxJS. Para fazer isso funcionar, precisamos adicionar o método “of”, conforme demonstrado no seguinte exemplo da documentação do RxJS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>Implementei o operador “of” na versão atualizada e fiz algumas modificações na forma como os métodos são executados dentro do Observable. Basicamente, eu os chamo por meio de um método de envoltório via uma “chamada” para garantir que o objeto assinante seja “this” nos métodos next, complete e error. Confira o seguinte exemplo:</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>Você deve obter o seguinte log de console ao executá-lo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>Na página Observable do RxJS, há outra ilustração de comportamento que usa o método “interval”. Esse método retorna um objeto de assinatura que é cancelado após 2,5 segundos usando a função setTimeout.</p><p>Para isso funcionar, precisamos incluir o operador interval que gera a assinatura, da qual podemos cancelar a inscrição posteriormente.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>Aqui está o exemplo funcionando usando a biblioteca RxJS padrão:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>Aqui temos uma instância de nossa biblioteca personalizada do rxjs em ação, conforme demonstrado por este exemplo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>É incrível que ambos produzirão saída — isso demonstra o quanto nossa biblioteca personalizada do rxjs se expandiu. Agora podemos usar o operador interval para enviar números através do Observable e cancelar a inscrição quando necessário.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>Em conclusão, criar uma biblioteca de Observable personalizada do zero é um ótimo exercício para entender o funcionamento interno dos Observables e como eles lidam com fluxos de dados assíncronos. Com apenas algumas linhas de código, conseguimos obter funcionalidades básicas de Observable e melhorá-las para atender à maioria dos casos de uso.</p><p>A beleza dos Observables está em sua flexibilidade e facilidade de uso. Eles podem ser usados para lidar com fluxos de dados em uma variedade de cenários, desde emissões simples de dados até solicitações de rede complexas. Ao entender como os Observables funcionam, podemos desbloquear um novo nível de funcionalidade em nossas aplicações.</p><p>Obrigado por ler e espero que este artigo tenha lhe dado uma melhor compreensão dos Observables e como criar sua própria biblioteca personalizada de Observable.</p><h3>Confira meu framework de código aberto QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>Confira meus outros artigos</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>Por favor, dê um 👏 no artigo e compartilhe-o!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c40262983556" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[لا تقم بتعديل العناوين التي تبدأ بـ “ — “: (Arabic)]]></title>
            <link>https://medium.com/@jsmuster/%D9%84%D8%A7-%D8%AA%D9%82%D9%85-%D8%A8%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%86%D8%A7%D9%88%D9%8A%D9%86-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%A8%D8%AF%D8%A3-%D8%A8%D9%80-arabic-a7ca1be8beac?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/a7ca1be8beac</guid>
            <category><![CDATA[application-development]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[arabic]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Sat, 25 Mar 2023 05:32:17 GMT</pubDate>
            <atom:updated>2023-03-25T05:32:17.661Z</atom:updated>
            <content:encoded><![CDATA[<h3>لا تقم بتعديل العناوين التي تبدأ بـ “ — “: (Arabic)</h3><p>في هذه المقالة، سأستكشف مفهوم Observables من خلال إنشاء مكتبة صغيرة من البداية. سنغوص من خلال هذه التمرينات في العمليات الداخلية للobservables وكيفية إنشائها، وكيفية استخدامها لمعالجة تدفقات البيانات الغير متزامنة.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>فكيف يمكننا إنشاء Observables من البداية؟ دعونا نلقي نظرة على توثيق RxJS للحصول على وصف، حيث يوضح الصف Observable أنه يمتد من Subscribable، و Subscribable هو واجهة تحتوي على طريقة subscribe، لذلك يجب أن يحتوي Observable لدينا على طريقة subscribe، أليس كذلك؟</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>المُنشئ هو جانب آخر مهم، حيث يحتوي على معامل اختياري، وهو دالة يتم استدعاؤها عندما يتم الاشتراك في Observable.</p><p>تتلقى هذه الدالة كائن المشترك من نوع Observer، الذي يمكن استخدامه لإرسال قيم جديدة باستخدام الطريقة next، أو إشارة الخطأ باستخدام الطريقة error، أو إشارة الانتهاء بنجاح باستخدام الطريقة complete.</p><p>استنادًا إلى المعلومات السابقة، يجب أن يعمل Observable على النحو التالي:</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><ol><li>إنشاء Observable وتمرير الدالة إلى المنشئ التي ستقوم بإرسال القيم إلى المشترك في الObservable.</li><li>أخيرًا، الاشتراك في ال Observable من خلال تمرير الدالة التي ستستقبل القيم.</li></ol><p>طريقة المُنشئ تحفظ كمرجع، وتنتظر طريقة الاشتراك لتنفيذها.</p><p>في مثالي هذا، أنا أقوم بتمرير دالة إلى منشئ Observable، والتي تُنفذ مباشرة عند الاشتراك، ولكن عادةً ما توفرها المكتبة التنفيذية التي تحدد ما سيتم إرساله من Observable ومتى سيتم إرساله، وغالبًا ما تكون غير متزامنة.</p><p>على سبيل المثال، في السيناريو الحقيقي، ستقوم الخدمة التالية بتنفيذ طريقة الاشتراك بشكل غير متزامن، فقط عندما يتم استقبال البيانات بنجاح من خدمة HTTP.</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>أو هناك Observable سيقوم بإرسال قيمة كل ثانية بعد الاشتراك فيه:</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>الآن، دعونا نقوم بتنفيذ Observable وننفذ هذه الأمثلة.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>إليك الكود المستخدم في مكتبة rxjs لتنفيذ ذلك:<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>وإليك نسختي من مكتبة Observable المُنفذة بشكل مخصص:<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>كلاهما يعمل بنفس الطريقة. يتم الحصول على النتائج التالية في كل من الأمثلة:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>دعونا الآن نلقي نظرة على المثال الذي يُرسل فيه Observable قيمة كل ثانية:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>نحصل على النتيجة التالية على مخرجات الكونسول:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>بمجرد استخدام 80 سطرًا من الكود، تمكنا من تحقيق وظائف ال Observable الأساسية وكل شيء يبدو يعمل بشكل ممتاز. رائع!</p><p>يعرض المقتطف التالي من توثيق RxJS للعمل، ولجعل هذا يعمل، يجب علينا إضافة طريقة “of” كما هو موضح في المثال التالي من توثيق RxJS.</p><p>لقد نفذت عامل “of” في النسخة المحدثة، وقمت بعمل بعض التعديلات على كيفية تنفيذ الطرق داخل Observable. أنا ببساطة أقوم بإستدعائهم عبر طريقة الإتصال “call” للتأكد من أن كائن المشترك هو “this” داخل طرق next، complete و error. تحقق من المثال التالي:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>لجعل هذا يعمل، يجب علينا إضافة طريقة “of” كما هو موضح في المثال التالي من توثيق RxJS. لقد قمت بتنفيذ عامل “of” في الإصدار المحدث، وقمت ببعض التعديلات على كيفية تنفيذ الطرق داخل Observable. بالأساس، أقوم بتنفيذها من خلال طريقة قابلة للتخصيص عن طريق “call” للتأكد من أن كائن المشترك هو “this” داخل طرق next و complete و error. تحقق من المثال التالي:</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>يجب عليك الحصول على النتيجة التالية عند تشغيله:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>على صفحة RxJS Observable، هناك رسم توضيحي آخر للسلوك الذي يستخدم عامل “interval”. هذا العامل يعيد كائن اشتراك يتم إلغاء اشتراكه بعد 2.5 ثانية باستخدام دالة setTimeout.</p><p>لجعل هذا يعمل، يجب علينا تضمين عامل الفاصل الزمني “interval” الذي يولد الاشتراك، والذي يمكننا فيما بعد إلغاء اشتراكنا منه.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>فيما يلي المثال الذي يعمل باستخدام مكتبة rxjs القياسية:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>هنا لدينا مثالًا على تطبيق مكتبة rxjs المخصصة لدينا، كما هو موضح في هذا المثال:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>مدهش كيف يمكن لكليهما أن ينتجا الإخراج — وهذا يوضح مدى توسع مكتبة rxjs المخصصة لدينا. يمكننا الآن استخدام عامل الفاصل الزمني لإرسال الأرقام من خلال Observable والإلغاء الاشتراك عند الضرورة.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>في الخلاصة، إن إنشاء مكتبة Observable مخصصة من الصفر هو تمرين رائع لفهم العمليات الداخلية لل Observables وكيفية معالج</p><p>جمال Observables يكمن في مرونتها وسهولة استخدامها. يمكن استخدامها لمعالجة تدفقات البيانات في مجموعة متنوعة من السيناريوهات، بدءًا من الإرسالات البسيطة للبيانات إلى الطلبات الشبكية المعقدة. من خلال فهم كيفية عمل Observables، يمكننا فتح مستوى جديد كليًا من الوظائف في تطبيقاتنا.</p><p>شكرًا لك على القراءة، وآمل أن يكون هذا المقال قد أعطاك فهمًا أفضل لل Observables وكيفية إنشاء مكتبة Observable المخصصة الخاصة بك.</p><h3>تحقق من إطار العمل المفتوح المصدر الخاص بي QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>تحقق من مقالاتي الأخرى.</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>يرجى إعطاء المقال بعض الإعجاب ومشاركته!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a7ca1be8beac" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[হেডারগুলি ছুঁকবেন না, যেগুলি ‘ — ‘ দিয়ে শুরু হয়েছে: (Bengali)]]></title>
            <link>https://medium.com/@jsmuster/%E0%A6%B9%E0%A7%87%E0%A6%A1%E0%A6%BE%E0%A6%B0%E0%A6%97%E0%A7%81%E0%A6%B2%E0%A6%BF-%E0%A6%9B%E0%A7%81%E0%A6%81%E0%A6%95%E0%A6%AC%E0%A7%87%E0%A6%A8-%E0%A6%A8%E0%A6%BE-%E0%A6%AF%E0%A7%87%E0%A6%97%E0%A7%81%E0%A6%B2%E0%A6%BF-%E0%A6%A6%E0%A6%BF%E0%A7%9F%E0%A7%87-%E0%A6%B6%E0%A7%81%E0%A6%B0%E0%A7%81-%E0%A6%B9%E0%A7%9F%E0%A7%87%E0%A6%9B%E0%A7%87-bengali-f7a99ce6f461?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/f7a99ce6f461</guid>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[bengali]]></category>
            <category><![CDATA[application-development]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Fri, 24 Mar 2023 05:56:56 GMT</pubDate>
            <atom:updated>2023-03-24T05:56:56.335Z</atom:updated>
            <content:encoded><![CDATA[<h3>হেডারগুলি ছুঁকবেন না, যেগুলি ‘ — ‘ দিয়ে শুরু হয়েছে: (Bengali)</h3><p>এই নিবন্ধে, আমি শুরু থেকে একটি ছোট্ট লাইব্রেরি তৈরি করে পর্যবেক্ষণ করবো অবজারভেবলগুলোর ধারণার উপর। এই অনুশীলনের মাধ্যমে, আমরা অবজারভেবলগুলোর আন্তরিক কার্যকিণী পর্যবেক্ষণ করব, যেখানে তারা কিভাবে তৈরি করা যায় এবং অসিনক্রন ডেটা স্ট্রিমগুলি হ্যান্ডেল করার জন্য কিভাবে ব্যবহার করা যায়।</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>এখন আমরা কীভাবে শুরু থেকে ওবসারভেবল তৈরি করতে হবে তা নিয়ে চিন্তা করব? রিসিপি পেতে আমরা এরকম কিছু দেখতে পারি যেমন RxJS ডকুমেন্টেশনে, যেখানে ওবসারভেবল ক্লাস একটি সাবস্ক্রাইবেবল ক্লাসের একটি এক্সটেনশন। এটি একটি ইন্টারফেস সাবস্ক্রাইব মেথড সহ যা একটি সাবস্ক্রাইব মেথড থাকা উচিত। তাই আমাদের ওবসারভেবলের সাবস্ক্রাইব মেথড থাকা উচিত, আমি সঠিক বলছি না?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>কনসট্রাক্টর হল একটি গুরুত্বপূর্ণ দিক, যা একটি ঐচ্ছিক প্যারামিটার দিয়ে থাকে, যা সাবস্ক্রাইব করা হলে ওবসারভেবলে কল করা হয়।</p><p>এই ফাংশনটি একটি অবজারভার টাইপের সাবস্ক্রাইবার অবজেক্ট পেয়ে এসে নতুন মান এমিট করতে এটি ব্যবহার করা যায় এক্সট মেথডটি ব্যবহার করে, অথবা ত্রুটি সংকেত ব্যবহার করে ত্রুটি সংকেত করতে ব্যবহার করা যায়, অথবা সফলভাবে সমাপ্তি নির্দেশ করতে ব্যবহার করা যায়।</p><p>উপরের তথ্যের উপর ভিত্তি করে অবজারভেবল এই ভাবে কাজ করবে:</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><ol><li>অবজারভেবলটি তৈরি করুন এবং অবজেক্টটির সাবস্ক্রাইবারে মান প্রেরণ করার জন্য কনস্ট্রাক্টরে একটি মেথড পাস করুন।</li><li>আবহাওয়ানি ডেটা স্ট্রিমগুলি হ্যান্ডেল করতে ব্যবহৃত হয়ে ওবসার্ভেবলে সাবস্ক্রাইব করুন পাসিং একটি মেথড।</li></ol><p>Observable তৈরি করার জন্য আমরা কীভাবে কাজ করব? একটি রেসিপির জন্য RxJS ডকুমেন্টেশন দেখি, যেখানে দেখা যায় যে Observable ক্লাস একটি Subscribable এর একটি এক্সটেন্ড করে এবং Subscribable হল একটি ইন্টারফেস যেখানে subscribe মেথড আছে, সুতরাং আমাদের Observable একটি subscribe মেথড থাকতে হবে। ঠিক আছি?</p><p>কনসট্রাক্টর আরেকটি গুরুত্বপূর্ণ দিক, এতে একটি ঐচ্ছিক প্যারামিটার আছে, যা হল যখন Observable সাবস্ক্রাইব করা হয় তখন কল করা হয়।</p><p>এই ফাংশনটি একটি Observer টাইপের subscriber অবজেক্ট পেয়ে, next মেথডটি ব্যবহার করে নতুন মান এমিট করতে পারে বা এরর মেথডটি ব্যবহার করে ত্রুটি সংকেত করতে পারে বা সফল সমাপ্তির জন্য সম্পূর্ণ মেথডটি ব্যবহার করতে পারে।</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>উপরের তথ্যের উপর ভিত্তি করে Observable এমনভাবে কাজ করবে:</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>এখন চলুন আমরা Observable টি ইমপ্লিমেন্ট করে এবং শেষমেষ কোড স্যাম্পলগুলি এক্সিকিউট করি।</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>রিএক্সজেএস লাইব্রেরি ব্যবহার করে এরকম স্যাম্পল কোডঃ<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>এবং এখানে আমার কাস্টম Observable ইমপ্লিমেন্টেশনসহ একই ফাংশনালিটি প্রদর্শিত হলঃ<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>উভয়ই একই ফাংশন করে। উভয় স্যাম্পলে আমরা নিম্নলিখিত কনসোল লগ পেয়েছি:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>এখন আসুন আমরা যে উদাহরণটি নিয়ে কাজ করি, যেটি Observable কোনও সময় একটি মান এমিট করবে।</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>একটি মান এমিট হওয়া সময় আমরা নিম্নলিখিত কনসোল আউটপুট পেয়েছি:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>মাত্র 80 লাইন কোড দিয়ে, আমরা বেসিক অবজারভেবল ফাংশনালিটি প্রাপ্ত করেছি এবং সবকিছু একটুখানি ভালভাবে কাজ করছে। অসাধারণ!</p><p>চলুন কিছু মজা করি এবং ফাংশনালিটি উন্নয়ন করি! আমরা আমাদের প্রকল্পগুলিতে সম্ভাব্যতম বেশি ব্যবহৃত কেসের জন্য সম্পূর্ণ আরএক্সজেএস প্যাকেজটি যোগ করতে না হয়ে, আমরা অবজারভেবল লাইব্রেরির একটি হালকা সংস্করণ তৈরি করতে পারি।</p><p>নিম্নলিখিত স্নিপেটটি আরএক্সজেএস নথিতে অংশ হয়, এটি কাজ করার জন্য, আমাদের কল করতে হবে “of” মেথডটি এর উদাহরণটি নির্দেশ করে।</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>আমি উন্নয়নকৃত সংস্করণে “of” অপারেটরটি বাস্তবায়ন করেছি এবং অবজারভেবলের ভিতরে মেথডগুলি কীভাবে নিষ্পাদিত হয় তা উন্নয়ন করেছি। মূলতঃ, আমি একটি “কল” মাধ্যমে এগুলি একটি ওয়্রাপার মাধ্যমে ডাক করি যাতে “পরবর্তী”, “সম্পূর্ণ” এবং “ত্রুটি” মেথডগুলির মধ্যে সাবস্ক্রাইবার অবজেক্ট “এই” হয়। নিচের উদাহরণটি দেখুন:</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>আপনি এটি চালানোর সময় নিম্নলিখিত কনসোল লগ পাবেন:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>RxJS অবজারভেবল পৃষ্ঠাতে, “ইন্টারভেল” মেথড ব্যবহার করে আরও একটি আচরণ বর্ণনা আছে। এই মেথডটি সেটটাইমাউট ফাংশন ব্যবহার করে 2.5 সেকেন্ডের পরে আনসাবস্ক্রাইব অবজেক্ট ফেরত দেয়।</p><p>এটি কাজ করার জন্য, আমাদের সাবস্ক্রিপশনটি উৎপন্ন করে দেওয়া “interval” অপারেটরটি অবশ্যই সংযোজন করতে হবে যা সাবস্ক্রাইব থেকে পরে অন-সাবস্ক্রাইব করা যাবে।</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>এখানে স্ট্যান্ডার্ড rxjs লাইব্রেরি ব্যবহার করে উদাহরণটি কাজ করেছে:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>এখানে আমাদের কাস্টম rxjs লাইব্রেরির একটি ইনস্ট্যান্স আছে, এটি নিম্নলিখিত উদাহরণে উপস্থাপিত হয়েছে:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>চমৎকার যে দুটি একই ফলাফল দিয়ে — এটি দেখায় কত আমাদের কাস্টম rxjs লাইব্রেরি বিস্তৃত হয়েছে। আমরা এখন সংখ্যা যানজট পাঠানোর জন্য interval অপারেটরটি ব্যবহার করতে পারি এবং প্রয়োজন হলে অন-সাবস্ক্রাইব করতে পারি।</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>সংকলনে, স্ক্র্যাচ থেকে কাস্টম Observable লাইব্রেরি তৈরি করা হলো যা অবসরপ্রাপ্ত তথ্য ঝরে নিয়ে সমস্ত অসমস্যার জন্য ব্যবহৃত হতে পারে। কয়েকটি লাইন কোড দিয়েই আমরা বেসিক Observable কার্যকারিতা অর্জন করতে পেরেছি এবং প্রয়োজনীয়তা অনুযায়ী এটি সুষ্ঠুভাবে উন্নয়ন করতে পারি।</p><p>Observables এর সৌন্দর্য হলো তাদের সফলভাবে ব্যবহার ও পরিবর্তনশীলতা। এগুলি সহজতর এবং এপ্লিকেশনগুলিতে সিম্পল ডেটা ইমিশন থেকে শুরু করে কমপ্লেক্স নেটওয়ার্ক রিকুয়েস্ট পর্যন্ত যেকোনো ধরনের ডেটা স্ট্রিম হ্যান্ডেল করতে ব্যবহৃত হতে পারে। অবজারভেবল কাজ করার নিয়ম বুঝে নিজেকে প্রশিক্ষিত করে নতুন করে ওবজারভেবল লাইব্রেরী তৈরি করা একটি উত্তম অনুশীলন। কয়েকটি কোড লাইন দিয়ে আমরা বেসিক অবজারভেবল ফাংশনালিটি সম্পন্ন করতে পারি এবং এটি মূলত সমস্ত ব্যবহারের জন্য উন্নয়নযোগ্য করে নেওয়া যায়।</p><p>পড়ার জন্য ধন্যবাদ এবং আশা করি এই নিবন্ধটি আপনাকে অবজার্ভেবল এবং নিজের কাস্টম অবজার্ভেবল লাইব্রেরি তৈরি করতে কিভাবে সম্পূর্ণ করতে সাহায্য করেছে। কয়েকটি লাইন কোড দিয়ে, আমরা বেসিক অবজার্ভেবল ফাংশনালিটি অর্জন করতে পেরেছি এবং এটি সম্ভবত সবচেয়ে বেশি ব্যবহৃত মামলাগুলির জন্য অবজার্ভেবল লাইব্রেরি পুরোপুরি RxJS প্যাকেজ সহ আমাদের প্রকল্পে যুক্ত করার প্রয়োজন নেই।</p><h3>চেক আউট মাই ওপেন সোর্স ফ্রেমওয়ার্ক QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>আমার অন্যান্য নিবন্ধগুলি দেখুন।</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>দয়া করে এই নিবন্ধটির কিছু 👏 দিয়ে এবং শেয়ার করুন!.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f7a99ce6f461" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Une plongée profonde dans les Observables RxJS : en recréant la bibliothèque RxJS à partir de zéro…]]></title>
            <link>https://medium.com/@jsmuster/une-plong%C3%A9e-profonde-dans-les-observables-rxjs-en-recr%C3%A9ant-la-biblioth%C3%A8que-rxjs-%C3%A0-partir-de-z%C3%A9ro-d7178645ee26?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/d7178645ee26</guid>
            <category><![CDATA[french]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[application-development]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Thu, 23 Mar 2023 05:46:48 GMT</pubDate>
            <atom:updated>2023-03-23T05:46:48.387Z</atom:updated>
            <content:encoded><![CDATA[<h3>Une plongée profonde dans les Observables RxJS : en recréant la bibliothèque RxJS à partir de zéro (French)</h3><p>Dans cet article, j’explorerai le concept d’Observables en créant une petite bibliothèque à partir de zéro. À travers cet exercice, nous plongerons dans le fonctionnement interne des Observables, comment ils peuvent être créés et comment ils peuvent être utilisés pour gérer les flux de données asynchrones.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>Alors, comment pouvons-nous créer des Observables à partir de zéro ? Jetons un coup d’œil à la documentation RxJS pour une recette, comme vous le voyez, une classe Observable étend une classe Subscribable, et Subscribable est une interface avec la méthode subscribe, donc notre Observable devrait avoir une méthode subscribe, n’est-ce pas ?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>Le constructeur est un autre aspect important, il a un paramètre facultatif, qui est une fonction qui est appelée lorsque l’Observable est abonné.</p><p>Cette fonction reçoit un objet abonné de type Observer, qui peut être utilisé pour émettre de nouvelles valeurs en utilisant la méthode next, ou signaler une erreur en utilisant la méthode error, ou indiquer une fin réussie en utilisant la méthode complete.</p><p>Sur la base des informations ci-dessus, l’Observable devrait fonctionner comme ceci :</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><ol><li>Créer l’Observable et passer une méthode dans le constructeur qui dispatchera les valeurs dans l’abonné de l’Observable.</li><li>Enfin, abonnez-vous à l’Observable en passant une méthode qui recevra les valeurs.</li></ol><p>La méthode subscribe invoque la fonction de constructeur passée à l’Observable. Cela signifie que s’abonner à un Observable est le moment où il commence à exécuter sa logique, plutôt que pendant la création, comme on le croit généralement. La méthode constructeur est sauvegardée en tant que référence et attend que la méthode subscribe l’exécute.</p><p>Dans mon exemple, je passe une fonction dans le constructeur de l’Observable, qui est exécutée immédiatement lorsque nous nous abonnons, MAIS elle est généralement fournie par une implémentation de bibliothèque qui spécifie ce que l’Observable émettra et quand il l’émettra. Et c’est souvent asynchrone.</p><p>Par exemple, dans un scénario du monde réel, le service suivant exécutera la méthode subscribe de manière asynchrone, uniquement lorsque des données sont reçues avec succès à partir d’un service HTTP.</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>ou voici un Observable qui émettra une valeur toutes les secondes après que nous nous y sommes abonnés :</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>Maintenant, implémentons l’Observable et exécutons enfin ces exemples de code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>Voici le code d’exemple utilisant la bibliothèque rxjs pour l’exécuter :<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>Et voici ma version avec une implémentation Observable personnalisée :<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>Les deux fonctionnent de la même manière. Nous obtenons le journal de console suivant dans les deux exemples :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>Maintenant, regardons l’exemple où Observable émet une valeur toutes les secondes :</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>Nous obtenons la sortie de console suivante :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>Avec seulement 80 lignes de code, nous avons été en mesure d’obtenir une fonctionnalité Observable de base et tout semble fonctionner parfaitement. Fantastique !</p><p>Amusons-nous un peu et améliorons la fonctionnalité ! Nous pouvons créer une version allégée de la bibliothèque Observables qui répond à la plupart de nos cas d’utilisation, sans avoir à inclure l’intégralité du package RxJS dans nos projets.</p><p>Le code suivant fait partie de la documentation RxJS. Pour que cela fonctionne, nous devons ajouter la méthode “of”, comme le montre l’exemple suivant de la documentation RxJS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>J’ai implémenté l’opérateur “of” dans la version mise à jour, et j’ai apporté des modifications à la façon dont les méthodes sont exécutées dans l’Observable. Essentiellement, je les appelle via une méthode d’enveloppe via un “appel” pour m’assurer que l’objet abonné est “this” dans les méthodes next, complete et error. Jetez un coup d’œil à l’exemple suivant :</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>Vous devriez obtenir le journal de console suivant lors de son exécution :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>Sur la page RxJS Observable, il y a une autre illustration de comportement qui utilise la méthode “interval”. Cette méthode renvoie un objet d’abonnement qui est désabonné après 2,5 secondes en utilisant la fonction setTimeout.</p><p>Pour que cela fonctionne, nous devons inclure l’opérateur “interval” qui génère l’abonnement, que nous pouvons ensuite désabonner.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>Voici l’exemple qui fonctionne en utilisant la bibliothèque RxJS standard :</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>Ici, nous avons une instance de notre bibliothèque RxJS personnalisée en action, comme le montre cet exemple :</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>C’est incroyable que les deux produisent une sortie — cela démontre à quel point notre bibliothèque RxJS personnalisée s’est étendue. Nous pouvons maintenant utiliser l’opérateur interval pour envoyer des nombres à travers l’Observable et nous désabonner lorsque cela est nécessaire.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>En conclusion, la création d’une bibliothèque Observable personnalisée à partir de zéro est un excellent exercice pour comprendre le fonctionnement interne des Observables et comment ils gèrent les flux de données asynchrones. Avec seulement quelques lignes de code, nous avons pu obtenir une fonctionnalité Observable de base et l’améliorer pour répondre à la plupart des cas d’utilisation.</p><p>La beauté des Observables réside dans leur flexibilité et leur facilité d’utilisation. Ils peuvent être utilisés pour gérer des flux de données dans une variété de scénarios, de simples émissions de données à des demandes réseau complexes. En comprenant le fonctionnement des Observables, nous pouvons débloquer un tout nouveau niveau de fonctionnalité dans nos applications.</p><p>Merci de lire et j’espère que cet article vous a donné une meilleure compréhension des Observables et comment créer votre propre bibliothèque Observable personnalisée.</p><h3>Découvrez mon framework open source QQ :</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>Découvrez mes autres articles :</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>Veuillez donner à l’article quelques 👏 et le partager !</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d7178645ee26" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Un Profundo Análisis de Observables en RxJS: al recrear la biblioteca RxJS desde cero (Spanish)]]></title>
            <link>https://medium.com/@jsmuster/un-profundo-an%C3%A1lisis-de-observables-en-rxjs-al-recrear-la-biblioteca-rxjs-desde-cero-spanish-f98ecb4ee32e?source=rss-5ee60ea6c196------2</link>
            <guid isPermaLink="false">https://medium.com/p/f98ecb4ee32e</guid>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[spanish]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[application-development]]></category>
            <dc:creator><![CDATA[Arseniy Tomkevich]]></dc:creator>
            <pubDate>Wed, 22 Mar 2023 05:46:59 GMT</pubDate>
            <atom:updated>2023-03-22T05:46:59.058Z</atom:updated>
            <content:encoded><![CDATA[<p>En este artículo, exploraré el concepto de Observables creando una pequeña biblioteca desde cero. A través de este ejercicio, profundizaremos en el funcionamiento interno de los observables, cómo se pueden crear y cómo se pueden utilizar para manejar flujos de datos asincrónicos.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gpx4kDfsJoaHa2e-.jpg" /></figure><p>Entonces, ¿cómo creamos Observables desde cero? Echemos un vistazo a la documentación de RxJS para obtener una receta. Como verás, la clase Observable extiende un Subscribable, y Subscribable es una interfaz con el método subscribe, por lo que nuestro Observable debería tener un método subscribe, ¿verdad?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*vVI663r6ps2069g_mUraYA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*PJFUYbL3f6hdxU3u_5adPw.png" /></figure><p>El constructor es otro aspecto importante, tiene un parámetro opcional que es una función que se llama cuando el Observable se suscribe.</p><p>Esta función recibe un objeto suscriptor del tipo Observer, que se puede utilizar para emitir nuevos valores utilizando el método next, o para señalar un error utilizando el método error, o para indicar la finalización exitosa utilizando el método complete.</p><p>Basándonos en la información anterior, el Observable debería funcionar de la siguiente manera:</p><pre>let obs = rxjs.Observable.create((subscriber) =&gt; {<br>  <br>  subscriber.next(1);<br>  subscriber.next(2);<br>  subscriber.next(3);</pre><pre>subscriber.complete();<br>});</pre><pre>obs.subscribe((value) =&gt; {<br>  console.log(value);<br>});</pre><p>Crear el Observable y pasar un método al constructor que despachará los valores al suscriptor del observable.</p><p>Finalmente, suscríbete al Observable pasando un método que recibirá los valores.</p><p>El método subscribe invoca la función del constructor pasada al Observable. Lo que significa que suscribirse a un Observable es el punto en el que comienza a ejecutar su lógica, en lugar de durante la creación, como comúnmente se cree. El método constructor se guarda como una referencia y espera que se ejecute el método subscribe.</p><p>En mi ejemplo, estoy pasando una función al constructor del Observable, que se ejecuta de inmediato cuando nos suscribimos, PERO generalmente es proporcionada por una implementación de biblioteca que especifica qué emitirá el Observable y cuándo lo emitirá. Y a menudo es asíncrono.</p><p>Entonces, por ejemplo, en un escenario del mundo real, el siguiente servicio ejecutará el método subscribe de manera asíncrona, solo cuando se reciban datos de un servicio HTTP correctamente.</p><pre>getConfigFromServer() {</pre><pre>this.configService.getConfig()<br>    .subscribe((data: Config) =&gt; this.config = {<br>        heroesUrl: data.heroesUrl,<br>        textfile:  data.textfile,<br>        date: data.date,<br>    });</pre><pre>}</pre><p>o aquí hay un Observable que emitirá un valor cada segundo después de que nos suscribamos a él:</p><pre>var observable = rxjs.Observable.create((subscriber) =&gt;{<br>  let count = 0;<br>  let interval;<br>         <br>   interval = setInterval(()=&gt;{<br>        subscriber.next(&#39;Hello world (&#39; + count++ + &#39;)&#39;);<br>        <br>        if(count &gt; 5)<br>        {<br>         clearInterval(interval);<br>          <br>          subscriber.complete();<br>    }<br>   }, 1000);</pre><pre>});</pre><p>Ahora, implementemos el Observable y finalmente ejecutemos estos ejemplos de código.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*XkroyFyftoS5mPUctTGBqQ.png" /></figure><p>Aquí está el código de muestra que usa la biblioteca rxjs para ejecutarlo:<br><a href="https://jsfiddle.net/jsmuster/tgkc05vy/">https://jsfiddle.net/jsmuster/tgkc05vy/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftgkc05vy%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/758944bc2da5eec3fe180713cb452278/href">https://medium.com/media/758944bc2da5eec3fe180713cb452278/href</a></iframe><p>Y aquí está mi versión con implementación personalizada de Observable:<br><a href="https://jsfiddle.net/jsmuster/u39t6bh8/">https://jsfiddle.net/jsmuster/u39t6bh8/</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fu39t6bh8%2F9%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href">https://medium.com/media/f91303804c079efaf10d46ada9c6a169/href</a></iframe><p>Ambos funcionan igual. Obtenemos el siguiente registro en la consola en ambos ejemplos:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*Et6uPtao_hqD_40lgooRmQ.png" /></figure><p>Ahora, echemos un vistazo al ejemplo en el que el Observable emite un valor cada segundo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2F7w0uc6qm%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href">https://medium.com/media/7dd2ba2e607be6c673f9e5ca5dad1796/href</a></iframe><p>Obtenemos la siguiente salida en la consola:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*XHcdFfK4mkiu7nEVU_Ywfw.png" /></figure><p>Con solo 80 líneas de código, pudimos lograr una funcionalidad básica de Observable y todo parece funcionar perfectamente. ¡Fantástico!</p><p>¡Divirtámonos y mejoremos la funcionalidad! Podemos crear una versión simplificada de la biblioteca Observables que satisfaga la mayoría de nuestros casos de uso, sin tener que incluir el paquete completo de RxJS en nuestros proyectos.</p><p>El siguiente fragmento de código es parte de la documentación de RxJS, para hacer que funcione, necesitamos agregar el método “of”, como se muestra en el siguiente ejemplo de la documentación de RxJS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*_FK5sAdtGKOBKSde4f9ang.png" /></figure><p>He implementado el operador “of” en la versión actualizada y he hecho algunas modificaciones en cómo se ejecutan los métodos dentro del Observable. Esencialmente, los llamo a través de un método envoltorio a través de una “llamada” para asegurarme de que el objeto suscriptor sea “this” dentro de los métodos next, complete y error. Echa un vistazo al siguiente ejemplo:</p><pre>sub.complete = () =&gt; {<br>  subscriber.complete.call(subscriber);<br>};</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fe6Lbpvu7%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href">https://medium.com/media/f1f41c1194a0232ad5a6385f12bbef7d/href</a></iframe><p>Deberías obtener el siguiente registro en la consola cuando lo ejecutes:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*2Wmy_QFHItdtIjIexaPLKg.png" /></figure><p>En la página de Observables de RxJS, hay otra ilustración de comportamiento que emplea el método “interval”. Este método devuelve un objeto de suscripción que se cancela después de 2.5 segundos utilizando la función setTimeout.</p><p>Para que esto funcione, debemos incluir el operador de intervalo que genera la suscripción, que luego podemos cancelar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*-hxq4SSPV28WLcWgtMp7Eg.png" /></figure><p>Aquí está el ejemplo funcionando usando la biblioteca estándar de RxJS:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Ftp6f715u%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href">https://medium.com/media/9b8697f009d7d6f44be06b3697e3265d/href</a></iframe><p>Aquí tenemos una instancia de nuestra biblioteca RxJS personalizada en acción, como se demuestra en este ejemplo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembedded%2F&amp;display_name=jsFiddle&amp;url=https%3A%2F%2Fjsfiddle.net%2Fjsmuster%2Fotrv4ukn%2Fembed%2Fjs%2Fdark%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=jsfiddle" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href">https://medium.com/media/c7ed0ffdabf23c771855e643570dcc89/href</a></iframe><p>Es sorprendente que ambos produzcan salida, esto demuestra cuánto se ha expandido nuestra biblioteca RxJS personalizada. Ahora podemos utilizar el operador de intervalo para enviar números a través del Observable y cancelar la suscripción cuando sea necesario.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/686/1*8KiCRGKidF_SJ0UO9KTong.png" /></figure><p>En conclusión, crear una biblioteca personalizada de Observable desde cero es un gran ejercicio para comprender el funcionamiento interno de los Observables y cómo manejan flujos de datos asincrónicos. Con solo unas pocas líneas de código, pudimos lograr una funcionalidad básica de Observable y mejorarla para satisfacer la mayoría de los casos de uso.</p><p>La belleza de los Observables radica en su flexibilidad y facilidad de uso. Se pueden utilizar para manejar flujos de datos en una variedad de escenarios, desde emisiones simples de datos hasta solicitudes de red complejas. Al comprender cómo funcionan los Observables, podemos desbloquear un nuevo nivel de funcionalidad en nuestras aplicaciones.</p><p>Gracias por leer y espero que este artículo te haya dado una mejor comprensión de los Observables y cómo crear tu propia biblioteca personalizada de Observable.</p><h3>Echa un vistazo a mi marco de código abierto QQ:</h3><p><a href="https://github.com/jsmuster/qq">https://github.com/jsmuster/qq</a></p><h3>Echa un vistazo a mis otros artículos.</h3><ul><li><a href="https://javascript.plainenglish.io/angular-routing-in-5-minutes-fe7300a0d174">Angular Routing in 5 Minutes</a></li><li><a href="https://levelup.gitconnected.com/angular-injector-in-5-minutes-54d173c97541">Angular Injector In 5 Minutes</a></li><li><a href="https://javascript.plainenglish.io/searching-for-a-good-javascript-developer-the-interview-questions-1691f0b925e6">Searching for a good JavaScript Developer — the Interview Questions</a></li></ul><p>¡Por favor, dale al artículo algunos 👏 y compártelo!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*zG47EBxWrccPSyF9.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f98ecb4ee32e" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>