Maison  >  Article  >  interface Web  >  Résumé et partage pour comprendre plusieurs nœuds clés de nodejs

Résumé et partage pour comprendre plusieurs nœuds clés de nodejs

青灯夜游
青灯夜游avant
2022-07-06 20:36:502050parcourir

Résumé et partage pour comprendre plusieurs nœuds clés de nodejs

Cet article est une compréhension personnelle de nodejs dans le développement et l'apprentissage réels. Il est maintenant compilé pour référence future. Je serais honoré s'il pouvait vous inspirer.

E/S non bloquantes

E/S : Entrée/Sortie, l'entrée et la sortie d'un système.

Un système peut être compris comme un individu, comme une personne Lorsque vous parlez, c'est le résultat, et lorsque vous écoutez, c'est l'entrée.

La différence entre les E/S bloquantes et les E/S non bloquantes réside dans la capacité du système à recevoir d'autres entrées pendant la période allant de l'entrée à la sortie. Voici deux exemples pour illustrer ce que sont les E/S bloquantes et les E/S non bloquantes :

1 Préparer des repas

Résumé et partage pour comprendre plusieurs nœuds clés de nodejsTout d'abord, nous devons déterminer la portée d'un système. Dans cet exemple, la tante de la cafétéria considère cela comme un système avec le serveur du restaurant, l'entrée commande et la sortie sert la nourriture.

Ensuite, si vous pouvez accepter les commandes d'autres personnes entre la commande et le service de la nourriture, vous pouvez déterminer si cela bloque les E/S ou non. Pour la tante de la cafétéria, elle ne peut pas commander pour les autres étudiants lors de la commande. Ce n'est qu'après que l'étudiant a fini de commander et servi les plats qu'il peut accepter la commande de l'étudiant suivant, donc la tante de la cafétéria bloque les E/S.

Pour le serveur du restaurant, il peut servir le prochain invité après la commande et avant que le client ne serve le plat, le serveur dispose donc d'E/S non bloquantes.

2. Faites le ménage

Lorsque vous lavez des vêtements, vous n'avez pas besoin d'attendre la machine à laver. À ce moment-là, vous pouvez balayer le sol et organiser le bureau. sont lavés. À ce moment-là, allez étendre le linge, cela ne prend alors que 25 minutes au total.

Résumé et partage pour comprendre plusieurs nœuds clés de nodejsLa lessive est en fait une E/S non bloquante. Vous pouvez faire d'autres choses entre mettre les vêtements dans la machine à laver et terminer le lavage.

La raison pour laquelle les E/S non bloquantes peuvent améliorer les performances est qu'elles peuvent éviter des attentes inutiles.

La clé pour comprendre les E/S non bloquantes est  :

Déterminer une limite du système

pour les E/S. Ceci est très critique. Si le système est étendu, comme dans l'exemple de restaurant ci-dessus, si le système est étendu à l'ensemble du restaurant, alors le chef sera définitivement une E/S bloquante.
  • Pendant le processus d'E/S, d'autres E/S peuvent-elles être effectuées ?
  • E/S non bloquantes nodejs

Comment se manifestent les E/S non bloquantes nodejs ? Comme mentionné précédemment, un point important pour comprendre les E/S non bloquantes est de déterminer d'abord une limite système. La limite système du nœud est le

thread principal

. Si le schéma d'architecture ci-dessous est divisé en fonction de la maintenance des threads, la ligne pointillée à gauche est le thread nodejs et la ligne pointillée à droite est le thread c++.

Maintenant, le thread nodejs doit interroger la base de données. Il s'agit d'une opération d'E/S typique. Il n'attendra pas les résultats de l'E/S et continuera à traiter d'autres opérations. puissance de calcul à d’autres opérations thread C++ pour calculer.

Résumé et partage pour comprendre plusieurs nœuds clés de nodejsAttendez que le résultat soit publié et renvoyez-le au thread nodejs. Avant d'obtenir le résultat, le thread nodejs peut également effectuer d'autres opérations d'E/S, il est donc non bloquant.

nodejs thread

équivaut à ce que la partie gauche soit le serveur et le thread c++ étant le chef.

Ainsi, les E/S non bloquantes du nœud sont complétées en appelant des threads de travail C++.

Comment notifier le thread nodejs lorsque le thread c++ obtient le résultat ? La réponse est événementielle.

Event-driven

Blocking : Le processus se met en veille pendant les E/S, attendant que les E/S soient terminées avant de passer à l'étape suivante

Non-blocking : La fonction revient immédiatement pendant I ; /O, et le processus n’attend pas la fin des E/S.

Ensuite, comment connaître le résultat renvoyé, vous devez utiliser event driver.

Le soi-disant Event-driven peut être compris comme la même chose que l'événement de clic frontal. J'écris d'abord un événement de clic, mais je ne sais pas quand il sera déclenché. Seulement quand il sera déclenché, le thread principal exécutera la fonction événementielle.

Ce mode est également un mode observateur, c'est-à-dire que j'écoute d'abord l'événement, puis je l'exécute lorsqu'il est déclenché. Alors, comment mettre en œuvre un drive événementiel ? La réponse est

Programmation asynchrone

.

Programmation asynchrone

Comme mentionné ci-dessus, nodejs dispose d'un grand nombre d'E/S non bloquantes, les résultats des E/S non bloquantes doivent donc être obtenus via des fonctions de rappel Cette méthode d'utilisation des fonctions de rappel. est une programmation asynchrone . Par exemple, le code suivant obtient des résultats via une fonction de rappel :

glob(__dirname+'/**/*', (err, res) => {
    result = res
    console.log('get result')
})

Spécification du format de la fonction de rappel

Le premier paramètre de la fonction de rappel nodejs est l'erreur, et les paramètres suivants sont le résultat. Pourquoi faire ça ?

try {
  interview(function () {
       console.log('smile')
  })
} catch(err) {
    console.log('cry', err)
}

function interview(callback) {
    setTimeout(() => {
        if(Math.random() <p>Après l'exécution, il n'a pas été détecté et l'erreur a été générée globalement, provoquant le crash de l'ensemble du programme nodejs. </p><p><img src="https://img.php.cn/upload/image/244/886/980/1657110712466688.png" title="1657110712466688.png" alt="Résumé et partage pour comprendre plusieurs nœuds clés de nodejs"></p><p> n'est pas capturé par try catch car setTimeout rouvre la boucle d'événements. Chaque fois qu'une boucle d'événements est ouverte, un contexte de pile d'appels est régénéré try catch appartient à la pile d'appels de la boucle d'événements précédente et la fonction de rappel. de setTimeout est exécuté, la pile d'appels est différente. Il n'y a pas de try catch dans cette nouvelle pile d'appels, donc l'erreur est générée globalement et ne peut pas être interceptée. Pour plus de détails, veuillez vous référer à cet article <a href="https://juejin.cn/post/6995749646366670855" target="_blank" title="https://juejin.cn/post/6995749646366670855">Problèmes lors de l'utilisation de files d'attente asynchrones pour try catch</a>. </p><p>Alors que devons-nous faire ? Utilisez l'erreur comme paramètre : </p><pre class="brush:php;toolbar:false">function interview(callback) {
    setTimeout(() => {
        if(Math.random() <p> Mais c'est plus gênant, et cela doit être jugé dans le rappel, donc une convention mature est créée. Le premier paramètre est err. S'il n'existe pas, cela signifie que l'exécution est. réussi. </p><pre class="brush:php;toolbar:false">function interview(callback) {
    setTimeout(() => {
        if(Math.random() <h3 data-id="heading-5"><strong>Contrôle de processus asynchrone</strong></h3><p>La méthode d'écriture de rappel de nodejs apportera non seulement des zones de rappel, mais apportera également des problèmes de <strong>contrôle de processus asynchrone</strong>. </p><p>Le contrôle de processus asynchrone fait principalement référence à la façon de gérer la logique de concurrence lorsque la concurrence se produit. Toujours en utilisant l'exemple ci-dessus, si votre collègue interviewe deux entreprises, il ne sera pas interviewé par la troisième entreprise tant qu'il n'aura pas interviewé avec succès deux entreprises. Alors, comment écrire cette logique ? Il est nécessaire d'ajouter une variable count:</p><pre class="brush:php;toolbar:false">var count = 0
interview((err) => {
    if (err) {
        return
    }
    count++
    if (count >= 2) {
        // 处理逻辑
    }
})

interview((err) => {
    if (err) {
        return
    }
    count++
    if (count >= 2) {
        // 处理逻辑
    }
})

globalement. Écrire comme ci-dessus est très gênant et moche. Par conséquent, les méthodes d’écriture promise et async/await sont apparues plus tard.

promesse

La boucle d'événements en cours ne peut pas obtenir le résultat, mais la boucle d'événements future vous donnera le résultat. C'est très similaire à ce que dirait un salaud.

la promesse n'est pas seulement un salaud, mais aussi une machine d'état :

  • en attente
  • exécuté/résolu
  • rejeté
const pro = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('2')
    }, 200)
})
console.log(pro) // 打印:Promise { <pending> }</pending>

puis & .catch

  • la promesse d'état résolue appellera la première plus tard Une promesse dans l'état then
  • rejected appellera le premier catch
  • Toute promesse dans l'état rejet et non suivie de .catch provoquera une erreur globale dans l'environnement du navigateur ou du nœud. uncaught représente une erreur non interceptée.

Résumé et partage pour comprendre plusieurs nœuds clés de nodejs

L'exécution de then ou catch

renverra une nouvelle promesse L'état final de la promesse est déterminé par les résultats d'exécution des fonctions de rappel de then et catch :

    Si la fonction de rappel est toujours throw new. Erreur, la promesse est à l'état Rejeté
  • Si la fonction de rappel revient toujours, la promesse est dans l'état résolu
  • Mais si la fonction de rappel renvoie toujours une promesse, la
  • promesse sera cohérente avec l'état de promesse du retour de la fonction de rappel .
function interview() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                resolve('success')
            } else {
                reject(new Error('fail'))
            }
        })
    })
}

var promise = interview()
var promise1 = promise.then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('accept')
        }, 400)
    })
})
Le statut de la promesse1 est déterminé par le statut de la promesse en retour, c'est-à-dire le statut de la promesse1 après l'exécution de la promesse en retour. Quels en sont les avantages ? Cela peut

résoudre le problème de l'enfer des rappels.

var promise = interview()
    .then(() => {
        return interview()
    })
    .then(() => {
        return interview()
    })
    .then(() => {
        return interview()
    })
    .catch(e => {
        console.log(e)
    })
then Si le statut de la promesse renvoyée est rejeté, alors la première capture sera appelée et la suivante ne sera pas appelée. N'oubliez pas : les appels rejetés sont la première capture, et les appels résolus sont ensuite la première.

la promesse résout le contrôle de processus asynchrone

Si la promesse consiste simplement à résoudre les rappels de l'enfer, elle est trop petite pour sous-estimer la promesse. La fonction principale de la promesse est de résoudre le problème de contrôle de processus asynchrone. Si vous souhaitez interviewer deux entreprises en même temps :

function interview() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                resolve('success')
            } else {
                reject(new Error('fail'))
            }
        })
    })
}

promise
    .all([interview(), interview()])
    .then(() => {
        console.log('smile')
    })
    // 如果有一家公司rejected,就catch
    .catch(() => {
        console.log('cry')
    })

async/await

sync/await Qu'est-ce que c'est exactement :

console.log(async function() {
    return 4
})

console.log(function() {
    return new Promise((resolve, reject) => {
        resolve(4)
    })
})
Les résultats imprimés sont les mêmes, c'est-à-dire que async/await n'est que le sucre syntaxique de promesse.

Nous savons que try catch capture les erreurs

dépend de la pile d'appels et ne peut capturer que les erreurs situées au-dessus de la pile d'appels. Mais si vous utilisez wait, vous pouvez détecter des erreurs dans toutes les fonctions de la pile d'appels. Même si l'erreur est générée dans la pile d'appels d'une autre boucle d'événements, telle que setTimeout.

Après avoir transformé le code de l'entretien, vous pouvez voir que le code est très rationalisé.

try {
    await interview(1)
    await interview(2)
    await interview(2)
} catch(e => {
    console.log(e)
})
Et s'il s'agissait d'une tâche parallèle ?

await Promise.all([interview(1), interview(2)])

Boucle d'événements

En raison des E/0 non bloquantes de nodejs, vous devez utiliser une approche basée sur les événements pour obtenir les résultats d'E/S. Pour obtenir des résultats basés sur les événements, vous devez utiliser une programmation asynchrone. , comme les fonctions de rappel. Alors comment exécuter ces fonctions de rappel afin d’obtenir les résultats ? Ensuite, vous devez utiliser une boucle d'événements.

La boucle d'événements est la base clé pour réaliser la fonction d'E/S non bloquante de nodejs. Les E/S non bloquantes et la boucle d'événements sont toutes deux des capacités fournies par

cette bibliothèque C++. libuv

Résumé et partage pour comprendre plusieurs nœuds clés de nodejs

代码演示:

const eventloop = {
    queue: [],
    loop() {
        while(this.queue.length) {
            const callback = this.queue.shift()
            callback()
        }
        setTimeout(this.loop.bind(this), 50)
    },
    add(callback) {
        this.queue.push(callback)
    }
}

eventloop.loop()

setTimeout(() => {
    eventloop.add(() => {
        console.log('1')
    })
}, 500)

setTimeout(() => {
	eventloop.add(() => {
		console.log('2')
	})
}, 800)

setTimeout(this.loop.bind(this), 50)保证了50ms就会去看队列中是否有回调,如果有就去执行。这样就形成了一个事件循环。

当然实际的事件要复杂的多,队列也不止一个,比如有一个文件操作对列,一个时间对列。

const eventloop = {
    queue: [],
    fsQueue: [],
    timerQueue: [],
    loop() {
        while(this.queue.length) {
            const callback = this.queue.shift()
            callback()
        }
        this.fsQueue.forEach(callback => {
            if (done) {
                callback()
            }
        })
        setTimeout(this.loop.bind(this), 50)
    },
    add(callback) {
        this.queue.push(callback)
    }
}

总结

首先我们弄清楚了什么是非阻塞I/O,即遇到I/O立刻跳过执行后面的任务,不会等待I/O的结果。当I/O处理好了之后就会调用我们注册的事件处理函数,这就叫事件驱动。实现事件驱动就必须要用异步编程,异步编程是nodejs中最重要的环节,它从回调函数到promise,最后到async/await(使用同步的方法写异步逻辑)。

更多node相关知识,请访问:nodejs 教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer