Maison  >  Article  >  interface Web  >  Programmation asynchrone JS Promesse, Générateur, asynchrone/attente

Programmation asynchrone JS Promesse, Générateur, asynchrone/attente

不言
不言original
2018-07-07 09:56:361665parcourir

Cet article présente principalement Promise, Generator, async/await sur la programmation asynchrone JS. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer

Programmation asynchrone JS (2). ) - Promise, Generator, async/await

Dans le dernier article, nous avons parlé des connaissances pertinentes de la programmation asynchrone JS, comme ce qui est asynchrone, pourquoi utiliser la programmation asynchrone et comment utiliser JS dans le navigateur Implémenté de manière asynchrone.
Enfin, nous avons parlé de plusieurs modes de programmation asynchrone JS (mode rappel, événement et publication/abonnement). Dans cet article, nous continuerons à approfondir plusieurs autres modes de programmation asynchrone.

Promise

Promise est une solution de programmation asynchrone introduite par ES6. En fait, avant ES6, de nombreuses bibliothèques d'outils asynchrones avaient déjà implémenté diverses solutions similaires, et ES6 les a inscrites dans le standard de langage et unifié leur utilisation. Promise résout le problème des solutions imbriquées telles que les rappels et rend le code plus lisible, donnant une impression de déjà-vu lors de l'écriture de méthodes synchrones.

Commençons d'abord par comprendre brièvement l'utilisation de Promise dans ES6

var p = new Promise(function async(resolve, reject){    // 这里是你的异步操作
    setTimeout(function(){        if(true){
            resolve(val);
        }else{
            reject(error);
        }
    }, 1000)
})

p.then(function(val){    console.log('resolve');
}, function(){    console.log('reject');
})

Tout d'abord, ES6 stipule que Promise est un constructeur, qui accepte une fonction comme paramètre telle que le async fonction dans le code ci-dessus, cette fonction a deux paramètres, résoudre et rejeter correspondant respectivement aux deux états de succès et d'échec. Nous pouvons choisir d'exécuter résoudre ou rejeter à des moments différents pour déclencher l'action suivante et exécuter la fonction dans la méthode then. .

On peut simplement comparer la différence entre l'écriture de rappel et l'écriture de promesse

Pour l'écriture de rappel traditionnelle, elle s'écrit généralement comme ceci

asyncFn1(function () {
  asyncFn2(function() {
    asyncFn3(function() {        // xxxxx
    });
  });
});

Ou nous pouvons séparer chaque fonction de rappel et l'écrire indépendamment pour réduire le couplage, comme ceci :

function asyncFn1(callback) {    return function() {        console.log('asyncFn1 run');
        setTimeout(function(){
            callback();
        }, 1000);
    }
}function asyncFn2(callback) {    return function(){        console.log('asyncFn2 run');
        setTimeout(function(){
            callback();
        }, 1000);
    }
}function normalFn3() {    console.log('normalFn3 run');
}

asyncFn1(asyncFn2(normalFn3))()

Enfin, regardons comment la promesse est écrite

function asyncFn1() {    
console.log('asyncFn1 run');    
return new Promise(function(resolve, reject) {
        setTimeout(function(){
            resolve();
        }, 1000)
    })
}function asyncFn2() {    
console.log('asyncFn2 run');    
return new Promise(function(resolve, reject) {
        setTimeout(function(){
            resolve();
        }, 1000)
    })
}function normalFn3() {    console.log('normalFn3 run');
}

asyncFn1().then(asyncFn2).then(normalFn3);

En regardant les choses de cette façon, qu'il s'agisse de la première ou de la deuxième façon d'écrire, les gens auront l'impression que ce n'est pas très intuitif, et la façon d'écrire Promise est plus intuitive et sémantique.

Générateur

La fonction Générateur est également une fonction spéciale fournie par ES6, et son comportement grammatical est complètement différent des fonctions traditionnelles.

Regardons d'abord l'utilisation réelle de Generator

function* oneGenerator() {  
yield 'Learn';  
yield 'In';  
return 'Pro';
}var g = oneGenerator();

g.next();   // {value: "Learn", done: false}g.next();   // {value: "In", done: false}g.next();   // {value: "Pro", done: true}

La fonction Generator est une fonction spéciale. Elle a les caractéristiques suivantes :

  • , vous devez ajouter

    après function et l'utiliser avec le mot-clé * dans la fonction. yield

  • 在执行Generator函数的时候,其会返回一个Iterator遍历器对象,通过其next方法,将Generator函数体内的代码以yield为界分步执行

  • 具体来说当执行Generator函数时,函数并不会执行,而是需要调用Iterator遍历器对象的next方法,这时程序才会执行从头或者上一个yield之后到下一个yield或者return或者函数体尾部之间的代码,并且将yield后面的值,包装成json对象返回。就像上面的例子中的{value: xxx, done: xxx}

  • value取的yield或者return后面的值,否则就是undefined,done的值如果碰到return或者执行完成则返回true,否则返回false。

我们知道了简单的Generator函数的用法以后,我们来看下如何使用Generator函数进行异步编程。

首先我们先来看下使用Generator函数能达到怎样的效果。

// 使用Generator函数进行异步编程function* oneGenerator() {  yield asyncFn1();  yield asyncFn2();  yield normalFn3();
}// 我们来对比一下PromiseasyncFn1().then(asyncFn2).then(normalFn3);

我们可以看出使用Generator函数进行异步编程更像是在写同步任务,对比Promise少了很多次then方法的调用。

好,那么接下来我们就来看下如何实际使用Generator函数进行异步编程。

这里我要特别说明一下,事实上Generator函数不像Promise一样是专门用来解决异步处理而产生的,人们只是使用其特性来产出了一套异步的解决方案,所以使用Generator并不像使用Promise一样有一种开箱即用的感觉。其更像是在Promise或者回调这类的解决方案之上又封装了一层,让你可以像上面例子里一样去那么写。

我们还是具体来看下上面的例子,我们知道单写一个Generator是不能运行的对吧,我们需要执行他并且使用next方法来让他分步执行,那么什么时候去调用next呢?答案就是我们需要在异步完成时去调用next。我们来按照这个思路补全上面的例子。

var g;function asyncFn() {
    setTimeout(function(){
        g.next();
    }, 1000)
}function normalFn() {    console.log('normalFn run');
}function* oneGenerator() {  yield asyncFn();  return normalFn();
}

g = oneGenerator();

g.next();// 这里在我调用next方法的时候执行了asyncFn函数// 然后我们的希望是在异步完成时自动去再调用g.next()来进行下面的操作,所以我们必须在上面asyncFn函数体内的写上g.next(); 这样才能正常运行。// 但其实这样是比较奇怪的,因为当我定义asyncFn的时候其实是不知道oneGenerator执行后叫什么名儿的,即使我们提前约定叫g,但这样asyncFn就太过于耦合了,不仅写法很奇怪而且耦合太大不利于扩展和重用。反正总而言之这种写法很不好。

那么怎么解决呢,我们需要自己写个方法,能自动运行Generator函数,这种方法很简单在社区里有很多,最著名的就是大神TJ写的co模块,有兴趣的同学可以看下其源码实现。这里我们简单造个轮子:

// 如果我们想要去在异步执行完成时自动调用next就需要有一个钩子,回调函数的callback或者Promise的then。function autoGenerator(generator){  var g = generator();  function next(){    var res = g.next();  // {value: xxx, done: xxx}

    if (res.done) {        return res.value;
    }    if(typeof res.value === 'function'){    // 认为是回调
        res.value(next);
    }else if(typeof res.value === 'object' && typeof res.value.then === 'function'){     // 认为是promise
        res.value.then(function(){
            next();
        })
    }else{
        next();
    }
  }

  next();
}// ----function asyncFn1(){    console.log('asyncFn1');    return new Promise(function(resolve){
        setTimeout(function(){
            resolve();
        }, 1000)
    })
}function asyncFn2() {    console.log('asyncFn2');    return function(callback){
        setTimeout(function(){
            callback();
        }, 1000);
    }
}function normalFn() {    console.log('normalFn');
}function* oneGenerator() {  yield asyncFn1();  yield asyncFn2();  yield normalFn();
}

autoGenerator(oneGenerator);

这个方法我们简单实现了最核心的部分,有些判断可能并不严谨,但大家理解这个思路就可以了。有了这个方法,我们才可以方便的使用Generator函数进行异步编程。

Async/Await

如果你学会了Generator函数,对于Async函数就会很容易上手。你可以简单把Async函数理解成就是Generator函数+执行器。我们就直接上实例好了

function asyncFn1(){    console.log('asyncFn1');    return new Promise(function(resolve){
        setTimeout(function(){
            resolve('123');
        }, 2000)
    })
}function asyncFn2() {    console.log('asyncFn2');    return new Promise(function(resolve){
        setTimeout(function(){
            resolve('456');
        }, 2000)
    })
}

async function asyncFn () {    var a = await asyncFn1();    var b = await asyncFn2();    console.log(a,b)
}

asyncFn();// asyncFn1// asyncFn2// 123,456

当然async里实现的执行器肯定是跟咱们上面简单实现的有所不同,所以在用法上也会有些注意的点

  • 首先async函数的返回值是一个Promise对象,不像是generator函数返回的是Iterator遍历器对象,所以async函数执行后可以继续使用then等方法来继续进行下面的逻辑

  • await est généralement suivi d'un objet Promise. Lorsque la fonction asynchrone est exécutée, après avoir rencontré wait, elle attend que l'état de l'objet Promise suivant passe de en attente à résolu, puis renvoie la résolution. paramètres et s'exécute automatiquement jusqu'à la prochaine attente ou fin

  • l'attente peut également être imbriquée avec une fonction asynchrone.

Pour l'asynchrone, il existe encore de nombreux points de connaissances que nous n'avons pas abordés, tels que la gestion des exceptions, l'exécution parallèle multi-asynchrone, etc. Cet article et l'article précédent se concentrent principalement sur J'espère que tout le monde a une compréhension intuitive de la programmation asynchrone et connaît les différences, les avantages et les inconvénients entre les différentes solutions. En raison de l'espace et de l'énergie limités, pour d'autres points de connaissances que nous n'avons pas abordés, si vous êtes intéressé et en avez l'occasion, j'écrirai un autre article pour vous expliquer en profondeur.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Introduction à la programmation asynchrone JS

Introduction de base à React-Reflux

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