Promiseとその使用


Promiseとその使用
なぜPromiseが必要なのか
Promiseの提案は非同期シーンという分野の問題を解決するためである.この章ではまず現在のJSが非同期を処理する際にどのような問題があるかを説明し,その後Promiseがこれらの問題を処理する方案を与える.
なぜ非同期が必要なのか
  • 単一スレッド+イベント駆動(ブラウザJS,NodeJs,Redis,Nginx...)
  • 従来の非同期処理スキーム
  • コールバック方式callback
  • マルチスレッド(JS以外)
  • CallBackスキームの問題点
  • コールバックピラミッド
  • フォーマット定義不統一(スタイル)
  • 非同期構文(スタイル)
  • 制御権(制御反転)-トリガ回数?トリガタイミング?トリガ周波数?
  • function wait1000(cb){
         setTimeout(cb, 1000);
    }
    function wait1000(cb){
         setInterval(cb, 1000);
    }
    function f1(){console.log('f1');}
    wait1000(f1);
    

    callbackの呼び出し関数(wait 1000)とcallbackを実現する関数(f 1)は一緒ではなく、callbackの実行は実装者(f 1)ではなく呼び出し元(wait 1000)に依存し、言い換えれば、私は関数を作成したが、この関数がどのように、いつ呼び出され、何回呼び出されるかは決定できない.これにより、コードの状態が信頼できなくなります.
    例:
    cb引き落とし業務への転送
    オーダーの作成-開発グループ1
    引き落とし-開発グループ2
    引き落とし成功-開発グループ2
    cbを呼び出して在庫を減らす--開発グループ1
    引き落としに失敗しました--開発チーム2
    開発グループ1が受注の作成と在庫の削減を担当すると仮定し、開発グループ2は控除業務を担当し、控除業務は非同期であり、コールバック関数cbに転送して控除結果を与える必要がある.ビジネスプロセスは、開発グループ1が受注を作成した後に在庫を1つ減らす動作を開発グループ2にコールバックとして渡すための引き落としモジュールである.通常はすべて正常ですが、開発グループ2で実装されたコードが間違っている場合、以下の可能性があります.
  • コールバックcb正常実行1回
  • コールバックcb実行(0回)
  • なし
  • コールバックcbはN回N>1
  • を実行する.
    開発グループ1としては、後の2つのシーンを処理する必要があるが、このロジックを組織するのは煩雑である.(変数記録+タイマ).煩雑な原因は、2つの異なる非同期プロセスを調整することであり、callbackモードでは2つ以上のcallbackをどのように調整するかの一般的なスキームが与えられていない.
    Promiseの定義
    英語のpromiseの意味は承諾で、1つは未来(非同期)で現金化した結果です.承諾には2つの状態があります:進行中、承諾を終了する結果には2つの可能性があります:成功して現金化して、約束を失います
    正常終了fullfill
    異常発生reject
    pending
    resolved
    rejected
    Promiseの2つの状態:pending,settled settledの2つの結果:resolved,rejected
    Promiseは常に1つの結果があり、結果は変更できず、結果は何度も発生できない.
    MDN Promise
    定義#テイギ#
    function showContent(t){
        console.log('  :', t);
    }
    function showError(err){
        console.log('    :', err);
    }
    
    //Promise.prototype.constructor
    var p = new Promise(function(resovle, reject){
        fs.readFile('/tmp/l.log','utf8', function(err, data){
            if(err){
                reject(err);
            }else{
                resolve(data);
            }
        });
    });
    p.then(showContent, showError);
    
    console.log(typeof p);
    console.log(p);
    console.log(p.)
    

    ≪ステータス|Status|emdw≫
    Promiseオブジェクト
    正常に進行する
    異常が発生する
    作成
    resolved
    rejected
    Promiseの簡単な使用
  • チェーンコール(then/catchはPromiseを返します)
  • p1.then(()=>p2).then(...)
    

    正常に進行する
    異常が発生する
    正常に進行する
    異常が発生する
    作成
    作成
    rejected
    resolved
    rejected
    //Promise.prototype.then(onFulfilled, onRejected)
    //Promise.prototype.catch(onRejected)
    //Promise.prototype.finally(onFinally) --- ES2018
    
    p.then(f1, f2)
    p.then(f1)
    p.catch(f2)
    p.then(f1).catch(f3)
    p.catch(f2).finally(f4)
    

    各種Promise方式のAPI
    fetch node-fetch fs.promises
    fetch('http://127.0.0.1:8080/api/get_user_list')
      .then(x=>x.json())
      .then(x=>console.log(x));
    

    複数のPromiseを組織
    複数の非同期オペレーションシリアルを編成するには、次の手順に従います.
    p.then().then().then()...
    

    並列:
    //        
    Promise.all([p1, p2, p3, ...]),then()
    
    //         
    Promise.race([p1, p2, p3, ...]).then()
    
    //        
    function p(name){
        return new Promise(function(resolve, reject){
            setTimeout(() => {
                console.log('Time: ', new Date(), name);
                resolve(Date.now());
            }, 1000);
        })
    }
    let tasks = ['A','B','C','D','E','F'];
    async function quee(){
        while(tasks.length>0){
            await p(tasks[0]);
            tasks.unshift();
        }
    }
    quee().then(()=>{
        console.log('END, Time: ', new Date());
    });
    
    

    へんしゅ
  • 制御時間の長い非同期操作promise+settimeout
  • function inTime1000(){
        return new Promise(function(resolve, reject){
            setTimeout(() => {
                reject(null);
            }, 1000);
        })
    }
    
    Promise.race([
       inTime1000(),
       fetch('http://127.0.0.1:8080/api/get_user_list').then(x=>x.json())
    ]).then(data=>{
          console.log(data);
    }, err=>{
      console.log(err);
    });
    

    一般的な関数としてパッケージ:inTime(p,timeOutSecond)
    function inTime(p, timeOutSecond){
    function inTimeTimer(second){
        return new Promise(function(resolve, reject){
            setTimeout(() => {
                reject(null);
            }, 1000*second);
        })
    }
    
    return Promise.race([inTimeTimer(1.5), p]);
    }
    
    //inTime( fetch('http://127.0.0.1:8080/api/get_user_list').then(x=>x.json()), 1.2).then();
    

    Promiseベースの他の非同期シーン処理
    function p(name, cb){
            setTimeout(() => {
                console.log('Time: ', new Date(), name);
                cb();
            }, 1000);
    }
    let tasks = ['A','B','C','D','E','F'];
    function next(){
        if(tasks.length>0){
            let t = tasks.shift();
            p(t, function(){
                console.log('  :', tasks);
                next();
            });
        }else{
            console.log('END, Time: ', new Date());
        }
    }
    next();
    
    setTimeout(()=>{
        tasks.push('M');
    },2100);
    
    

    await同期形式の非同期呼び出しは、書く形式が思考に合っている.
    function p(name){
        return new Promise(function(resolve, reject){
            setTimeout(() => {
                console.log('Time: ', new Date(), name);
                resolve(Date.now());
            }, 1000);
        })
    }
    let tasks = ['A','B','C','D','E','F'];
    async function quee(){
        while(tasks.length>0){
            await p(tasks[0]);
            tasks.shift();
            console.log('  :', tasks);
        }
    }
    quee().then(()=>{
        console.log('END, Time: ', new Date());
    });
    
    setTimeout(()=>{
        tasks.push('M');
    },2100);
    

    リファレンスライブラリ
    bluebird Q polyfill