フロントエンド面接命題(二)-callback,promise,generator,async-await

9287 ワード

前言
この文章はフロントエンドアーキテクチャ、または段階的なフロントエンド開発者に適しています.vmwareフロントエンドアーキテクチャを面接したとき、callback、promise、generator、async-awaitについて聞かれました.
まずjavascriptの非同期の発展過程を振り返ってみましょう.
ES 6以前:
コールバック関数(callback);Nodejs expressではよく使われ、ajaxではよく使われます.
ES6:
promiseオブジェクト;Nodejsにはbluebird promiseの雛形が最初にあり、axiosでよく使われています.
generator関数;Nodejs koaフレームワークは使用率が高い.
ES7:
async/await構文;現在最もよく使われている非同期構文で、nodejs koa 2はこの構文を完全に使用しています.
コールバック関数callback
コールバック関数は実際にはパラメータです.1つの関数をパラメータとして別の関数に転送し、その関数が実行された後、転送されたこの関数を実行します.この過程をコールバックと呼ぶ.
コールバックの字面も理解して、先に本体の関数を処理して、更にコールバックの関数を処理して、例を挙げて、みんなが理解するのに便利です.
 
function A(callback){
    console.log("      ");
    callback();
}

function B(){
    console.log("      ");
}

A(B);
/*    
      
      
*/

 
上の例はよく理解して、まず主体関数Aを実行して、結果を印刷します:私はテーマ関数です;コールバック関数callback、すなわちBを実行し、結果を印刷します.コールバック関数です.
promiseオブジェクト
promiseオブジェクトは、非同期操作の最終的な完了(または最終的な失敗)とその結果の表現に使用されます.
簡単に言えば、非同期リクエストを処理します.私たちはよく断言をします.もし私が勝ったら、あなたは私と結婚して、負けたら、私はあなたと結婚します.これがpromiseの中国語の意味です:断言して、1つの成功、1つの失敗.
例を挙げると、皆さんの理解に便利です.
promiseコンストラクション関数のパラメータは1つの関数であり、プロセッサ関数と呼ばれ、プロセッサ関数は2つの関数resloveとrejectをパラメータとして受信し、非同期操作が順調に実行されるとreslove関数を実行し、非同期操作で異常が発生するとreject関数数を実行する.resolveで入力された値はthenメソッドで取得でき、rejectで入力された値はchatchメソッドで取得できます.
thenとcatchは同じpromiseオブジェクトを返すため、チェーン呼び出しを行うことができます.
 
function readFileByPromise("a.txt"){
    //      promise  
    return new Promise((resolve,reject)=>{
        fs.readFile(path,"utf8",function(err,data){
            if(err)
                reject(err);
            else
                resolve(data);
        })
    })
}
//     
readFileByPromise("a.txt").then( data =>{
    //        
    console.log(data);
}).catch( error =>{
    //
    console.log(error);
})

 
generator関数
ES 6の新しい特性generator関数(面接の時にここに掛けます)は、中国語でジェネレータと訳され、以前の関数の中のコードが呼び出されるか、呼び出されないか、一時停止できる場合はありません.generatorはコードを実行待ちに一時停止させ、ジェネレータを定義するのは簡単で、関数の名前に*番号を付けて、使用上も普通の関数とは違います.
例を挙げると、皆さんの理解に便利です.
 
function *Calculate(a,b){
  let sum=a+b;
  console.log(sum);
  let sub=a-b;
  console.log(sub);
}

 
上には簡単なgenerator宣言の例があります.
generator関数は直接呼び出すことはできません.generator関数を直接呼び出すと、そのオブジェクトのnext()メソッドを呼び出すだけで関数のコードを実行できます.
let gen=Calculate(2,7);

この関数を実行します.
gen.next();
/*  
9
-5
*/

実はgeneratorを単独で紹介するのはあまり価値がありません.key yieldと協力してこそ、generatorの価値を本当に発揮することができます.yieldは生Generator関数のコードロジックを複数の部分に分割し,以下に上のジェネレータ関数を書き換えることができる.
function *Calculate(a,b){
  let sum=a+b;
  yield console.log(sum);
  let sub=a-b;
  yield console.log(sub);
}
let gen=Calculate(2,7);
gen.next();
/*  
9*/

このコードが最初のyieldで実行されると停止することがわかりますが、中のすべてのコードを実行するにはnext()メソッドを繰り返し呼び出さなければなりません.
let gen=Calculate(2,7);
gen.next();
gen.next();
/*  
9
-5*/

一例では、generator関数とコールバック関数の違いを説明します.
コールバック関数:
fs.readFile("a.txt",(err,data)=>{
    if(!err){
        console.log(data);
        fs.readFile("b.txt",(err,data)=>{
            if(!err)
                console.log(data);
        })
    }
})

これは典型的なコールバックネストであり、多すぎるコールバックネストはコードの可読性とメンテナンス性を大幅に低下させ、憎らしいコールバック地獄を形成している.ある日、10個のファイルを順番に読み取らせたら、10層をネストしなければならない.また、需要がさらに大きくなり、読み取り順序が変わったらb.txtを先に読み、再びa.txtを変えなければならないと考えてみてください.それは本当に爽やかではありません.
generator関数:
function readFile(path) {
    fs.readFile(path,"utf8",function(err,data){
          it.next(data);
    })
}

function *main() {
    var result1 = yield readFile("a.txt");
    console.log(result1);

    var result2 = yield readFile("b.txt");
    console.log(result2);

    var result3 = yield readFile("c.txt");
    console.log(result3);
}

var it = main();
it.next(); 

generator関数の強さは、いくつかの実装の詳細を通じて非同期プロセスを隠すことができ、コードを単一スレッド、同期構文のコードスタイルを維持することができます.このような構文は、非同期の構文フォーマットを同時に操作する必要がなく、プログラムのステップ/文の流れを自然に表現することができます.
async-await
async関数はpromiseオブジェクトを返し、async関数で直接量を返すとasyncはPromiseを通過する.resolveはPromiseオブジェクトにカプセル化されます.この直接量はpromiseオブジェクトのthenメソッドを呼び出すことで取得できます.
async function test(){
    return "Hello World";
}

var result=test();
console.log(result);
//  Promise { 'Hello World' }

 
ではasync関数が値を返さないとどうなるのでしょうか.
async function test(){
   
}
var result=test();
console.log(result);
//  Promise { undefined }

awaitは現在のasyncの実行を一時停止し、awaitはawait後の式の処理が完了するまでコードの実行をブロックし、コードは下に実行されません.await後の式は、Promiseオブジェクトでも待機する値でも構いません.awaitがPromiseオブジェクトである場合、awaitは忙しくなり、後のコードをブロックしてPromiseオブジェクトresolveを待ってからresolveの値をawait式の演算結果として得ます.
ブロックという言葉を見て、慌てないでください.async/awaitは文法糖にすぎません.コードの実行は複数のcallbackネスト呼び出しと区別されていません.本質は同期コードではありません.コードの論理を考えるときに同期の思考で考えることができます.復調地獄を避けることができます.簡単に言えば、async/awaitは同期の思考で非同期のコードを書くことです.だからasync/awaitはnodeの同時数に影響しないで、みんなは大胆にプロジェクトに応用することができます!
Promiseオブジェクトでない場合、await式の演算結果は待つものです.
例を挙げると、皆さんの理解に便利です.
function A() {
    return "Hello ";
}

async function B(){
    return "World";
}

async function C(){
    //       
    var s1=await A();
    //    promise  ,await     promise  resolve  ,   "World"
    var s2=await B();
    console.log(s1+s2);
}

C();
//  "Hello World"

 
転載先:https://www.cnblogs.com/peiyu1988/p/9204976.html