Heim  >  Artikel  >  Web-Frontend  >  JS asynchrone Programmierung Promise, Generator, async/await

JS asynchrone Programmierung Promise, Generator, async/await

不言
不言Original
2018-07-07 09:56:361590Durchsuche

Dieser Artikel stellt hauptsächlich Promise, Generator und Async/Await über die asynchrone JS-Programmierung vor. Er hat einen bestimmten Referenzwert. Jetzt können Freunde in Not darauf verweisen ) – Promise, Generator, async/await

Im letzten Artikel haben wir über die relevanten Kenntnisse der asynchronen JS-Programmierung gesprochen, z. B. was asynchron ist, warum man asynchrone Programmierung verwendet und wie man JS verwendet im Browser Asynchron implementiert.
Abschließend haben wir über mehrere asynchrone JS-Programmiermodi gesprochen (Callback-, Event- und Publish/Subscribe-Modus). In diesem Artikel werden wir uns weiterhin eingehender mit mehreren anderen asynchronen Programmiermodi befassen.


Promise

Promise ist eine von ES6 eingeführte asynchrone Programmierlösung. Tatsächlich hatten viele asynchrone Toolbibliotheken bereits vor ES6 verschiedene ähnliche Lösungen implementiert, und ES6 hat sie in den Sprachstandard geschrieben und ihre Verwendung vereinheitlicht. Promise löst das Problem verschachtelter Lösungen wie Rückrufe und macht den Code lesbarer, was beim Schreiben synchroner Methoden ein Déjà-vu-Gefühl vermittelt.

Lassen Sie uns zunächst kurz die Verwendung von Promise in ES6 verstehen

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');
})

Zunächst legt ES6 fest, dass Promise ein Konstruktor ist, der eine Funktion als Parameter wie die

-Funktion in akzeptiert Der obige Code verfügt über zwei Parameter, Auflösung und Ablehnung, die dem Erfolg bzw. Misserfolg entsprechen. Wir können die Auflösung oder Ablehnung zu unterschiedlichen Zeitpunkten ausführen, um die nächste Aktion auszulösen und die Funktion in der Methode „dann“ auszuführen.

asyncWir können einfach den Unterschied zwischen der Schreibweise von Rückrufen und der Schreibweise von Versprechen vergleichen

Beim traditionellen Schreiben von Rückrufen wird es normalerweise so geschrieben

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

Oder wir können jede Callback-Funktion trennen und unabhängig schreiben, um die Kopplung zu reduzieren, wie folgt:

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))()

Schließlich schauen wir uns an, wie Promise geschrieben wird

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);

Wenn man es so betrachtet, egal ob es sich um die erste oder die zweite Schreibweise handelt, wird es sich unintuitiv anfühlen, und die Schreibweise von Promise ist intuitiver und semantischer.

Generator

Die Generatorfunktion ist ebenfalls eine spezielle Funktion von ES6 und ihr grammatikalisches Verhalten unterscheidet sich völlig von herkömmlichen Funktionen.

Sehen wir uns zunächst die tatsächliche Verwendung von Generator an

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}

Die Generatorfunktion ist eine Sonderfunktion:

Bei der Deklaration von
    , Sie müssen
  • nach

    hinzufügen und es mit dem Schlüsselwort function in der Funktion verwenden. *

  • 在执行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等方法来继续进行下面的逻辑

  • Auf „await“ folgt normalerweise ein Promise-Objekt. Wenn die asynchrone Funktion ausgeführt wird, wartet sie nach der Begegnung mit „await“ darauf, dass sich der Status des nachfolgenden Promise-Objekts von „pending“ zu „resolved“ ändert, und gibt dann die Auflösung zurück Parameter und wird automatisch bis zum nächsten Warten oder Ende ausgeführt.

  • wait kann auch mit einer asynchronen Funktion verschachtelt werden.

Für Asynchronität gibt es noch viele Wissenspunkte, die wir nicht behandelt haben, wie z. B. Ausnahmebehandlung, multiasynchrone parallele Ausführung usw. Dieser und der vorherige Artikel konzentrieren sich hauptsächlich darauf Ich hoffe, dass jeder ein intuitives Verständnis der asynchronen Programmierung hat und die Unterschiede, Vor- und Nachteile zwischen verschiedenen Lösungen kennt. Aus Platz- und Energiegründen werde ich für andere Wissenspunkte, die wir nicht behandelt haben, bei Interesse und Gelegenheit einen weiteren Artikel schreiben, der ausführlich erläutert wird.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:

Einführung in die asynchrone JS-Programmierung

Grundlegende Einführung in React-Reflux

Das obige ist der detaillierte Inhalt vonJS asynchrone Programmierung Promise, Generator, async/await. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn