Maison  >  Article  >  interface Web  >  Analyse de traitement asynchrone en JavaScript

Analyse de traitement asynchrone en JavaScript

小云云
小云云original
2017-12-04 11:32:121702parcourir

Le traitement asynchrone consiste à gérer les problèmes selon des procédures asynchrones. Le traitement asynchrone et le traitement synchrone sont opposés, et ce qui les produit est multi-thread ou multi-processus. L'avantage du traitement asynchrone est d'augmenter l'utilisation du périphérique, améliorant ainsi l'efficacité du fonctionnement du programme au niveau macro, mais l'inconvénient est que des opérations conflictuelles et une lecture de données erronées sont susceptibles de se produire. Dans cet article, nous partagerons avec vous le traitement asynchrone en JavaScript.

Dans le monde de JavaScript, tout le code est exécuté dans un seul thread. En raison de cette « faille », toutes les opérations réseau et événements du navigateur en JavaScript doivent être exécutés de manière asynchrone. L'exécution asynchrone peut être implémentée à l'aide de fonctions de rappel

Les opérations asynchrones déclencheront un appel de fonction à un moment donné dans le futur

Les solutions de traitement asynchrone grand public comprennent principalement : la fonction de rappel (CallBack), la promesse et les fonctions de générateur , asynchrone/attendre.

1. Fonction de rappel (CallBack)

Il s'agit de la méthode la plus basique de programmation asynchrone

Supposons que nous ayons une méthode getData, qui est utilisée pour obtenir des données de manière asynchrone. le premier paramètre est l'adresse URL de la requête, et le deuxième paramètre est la fonction de rappel, comme suit :

function getData(url, callBack){    // 模拟发送网络请求
    setTimeout(()=> {        // 假设 res 就是返回的数据
        var res = {
            url: url,
            data: Math.random()
        }        // 执行回调,将数据作为参数传递
        callBack(res)
    }, 1000)
}

Nous définissons un scénario à l'avance Supposons que nous souhaitions demander au serveur trois fois, et chacune. La requête dépend du résultat de la requête précédente. Comme suit :

getData('/page/1?param=123', (res1) => {    console.log(res1)
    getData(`/page/2?param=${res1.data}`, (res2) => {        console.log(res2)
        getData(`/page/3?param=${res2.data}`, (res3) => {            console.log(res3)
        })
    })
})

Comme le montre le code ci-dessus, l'adresse URL de la première requête est : /page/1?param=123, et le résultat renvoyé est res1.

L'adresse URL de la deuxième requête est : /page/2?param=${res1.data}, qui dépend du res1.data de la première requête, et le résultat renvoyé est res2`.

L'adresse URL de la troisième requête est : /page/3?param=${res2.data}, qui dépend du res2.data de la deuxième requête, et le résultat renvoyé est res3.

Étant donné que les requêtes suivantes dépendent du résultat de la requête précédente, nous ne pouvons écrire la requête suivante qu'à l'intérieur de la fonction de rappel de la requête précédente, formant ainsi ce qu'on dit souvent : l'enfer du rappel.

2. Publier/Abonnez-vous

Nous supposons qu'il existe un "centre de signal". Lorsqu'une tâche est terminée, un signal est "publié" sur le centre de signal et d'autres tâches peuvent être envoyé au centre de signal. Le centre de signal « s'abonne » à ce signal afin de savoir quand il peut commencer son exécution. C'est ce qu'on appelle le « modèle de publication-abonnement » (modèle de publication-abonnement), également connu sous le nom de « modèle d'observateur » (modèle d'observateur)

Il existe de nombreuses implémentations de ce modèle. Ce qui suit est le Tiny Pub de Ben Alman. / Sub, ceci est un plug-in pour jQuery

Tout d'abord, f2 s'abonne à "Signal Center" jQuery done "Signal

jQuery.subscribe("done", f2);
f1进行如下改写
function f1(){                setTimeout(function(){                        // f1的任务代码                        jQuery.publish("done");                }, 1000);}
jQuery.publish("done") 的意思是, f1 执行完成后,向”信号中心 "jQuery 发布 "done" 信号,从而引发f2的执行。 此外,f2完成执行后,也可以取消订阅( unsubscribe )
jQuery.unsubscribe("done", f2);

La nature de cette méthode est la même comme "Event Listening" similaire, mais nettement meilleur que ce dernier. Parce que nous pouvons surveiller le fonctionnement du programme en consultant le « Centre de messages » pour voir combien de signaux existent et combien d'abonnés chaque signal possède.

3. Promise

Promise est une solution de programmation asynchrone, qui est plus raisonnable et plus puissante que les solutions traditionnelles - fonctions de rappel et événements

Ce qu'on appelle la promesse, en termes simples , est un conteneur qui stocke le résultat d'un événement (généralement une opération asynchrone) qui se terminera dans le futur. Syntaxiquement parlant, Promise est un objet à partir duquel des messages pour des opérations asynchrones peuvent être obtenus. Promise fournit une API unifiée et diverses opérations asynchrones peuvent être traitées de la même manière

En termes simples, l'idée est que chaque tâche asynchrone renvoie un objet Promise, qui a une méthode then qui permet de spécifier une fonction de rappel.

Nous utilisons maintenant Promise pour réimplémenter le cas ci-dessus. Tout d'abord, nous devons encapsuler la méthode de demande de données de manière asynchrone dans Promise

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

Ensuite, le code de requête doit être écrit comme ceci.

getDataAsync('/page/1?param=123')
    .then(res1=> {        console.log(res1)        return getDataAsync(`/page/2?param=${res1.data}`)
    })
    .then(res2=> {        console.log(res2)        return getDataAsync(`/page/3?param=${res2.data}`)
    })
    .then(res3=> {        console.log(res3)
    })

La méthode then renvoie un nouvel objet Promise. L'appel chaîné de la méthode then évite l'enfer du CallBack

Mais ce n'est pas parfait Par exemple, si on a besoin d'en ajouter beaucoup. de then déclarations, chacune doit alors encore être écrite un rappel.

Si le scénario est plus compliqué, par exemple, chaque requête suivante dépend des résultats de toutes les requêtes précédentes, pas seulement des résultats de la requête précédente, ce sera plus compliqué. Afin de faire mieux, async/await a vu le jour. Voyons comment utiliser async/await pour atteindre

4 async/await

La méthode getDataAsync reste inchangée, comme suit

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}
Le code métier est le suivant

fonction async getData(){ var res1 = wait getDataAsync('/page/1?param=123') console.log(res1) var res2 = attendre getDataAsync (`/page/2?param=${res1.data}`) console.log(res2) var res3 = attendre getDataAsync(`/page/2?param=${res2.data}`) console. log(res3 )

}

Vous pouvez voir qu'utiliser asyncawait, c'est comme écrire du code synchrone

Que pensez-vous de la comparaison de Promise ? C'est très clair, mais async/await est basé sur Promise, car la méthode décorée avec async renvoie finalement une Promise. En fait, async/await peut être considéré comme utilisant la fonction Generator pour gérer le sucre de syntaxe asynchrone. comment l'utiliser. La fonction Générateur gère l'asynchrone

5. Générateur

Premièrement, la fonction asynchrone est toujours

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}
L'utilisation de la fonction Générateur peut être écrite comme ceci

function*getData(){    var res1 = yield getDataAsync('/page/1?param=123')   
 console.log(res1)    var res2 = yield getDataAsync(`/page/2?param=${res1.data}`)   
  console.log(res2)    var res3 = yield getDataAsync(`/page/2?param=${res2.data}`)    console.log(res3))
}
🎜>

Ensuite, nous suivons cela étape par étape
var g = getData()
g.next().value.then(res1=> {
    g.next(res1).value.then(res2=> {
        g.next(res2).value.then(()=> {
            g.next()
        })
    })
})

上面的代码,我们逐步调用遍历器的 next() 方法,由于每一个 next() 方法返回值的 value 属性为一个 Promise 对象

所以我们为其添加 then 方法, 在 then 方法里面接着运行 next 方法挪移遍历器指针,直到 Generator 函数运行完成,实际上,这个过程我们不必手动完成,可以封装成一个简单的执行器

function run(gen){    var g = gen()    function next(data){        var res = g.next(data)        if (res.done) return res.value
        res.value.then((data) => {
            next(data)
        })
    }
    next()
}

run 方法用来自动运行异步的 Generator 函数,其实就是一个递归的过程调用的过程。这样我们就不必手动执行 Generator 函数了。 有了 run 方法,我们只需要这样运行 getData 方法

run(getData)

这样,我们就可以把异步操作封装到 Generator 函数内部,使用 run 方法作为 Generator 函数的自执行器,来处理异步。其实我们不难发现, async/await 方法相比于 Generator 处理异步的方式,有很多相似的地方,只不过 async/await 在语义化方面更加明显,同时 async/await 不需要我们手写执行器,其内部已经帮我们封装好了,这就是为什么说 async/await 是 Generator 函数处理异步的语法糖了

以上内容就是关于JavaScript中的异步处理,希望能帮助到大家。

相关推荐:

PHP异步处理的实现方案

详谈 Jquery Ajax异步处理Json数据

php 异步处理

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn