ES 6 Promiseの実戦筆記試験問題


ES 6 Promise練習
王八という諺があります.前の文章はそんなに長くPromiseを勉強しました.
基礎問題
問題1
const promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() => {
    console.log(3)
})
console.log(4)
解析:Promiseコンストラクタは同期して実行され、promise.thenの関数は非同期で実行されます.
実行結果:
// => 1
// => 2
// => 4
// => 3
問題2
const first = () => (new Promise((resolve, reject) => {
    console.log(3);
    let p = new Promise((resolve, reject) => {
        console.log(7);
        setTimeout(() => {
            console.log(5);
            resolve(6);
        }, 0)
        resolve(1);
    });
    resolve(2);
    p.then((arg) => {
        console.log(arg);
    });

}));

first().then((arg) => {
    console.log(arg);
});
console.log(4);
この問題は主にjsの実行メカニズムを理解しています.
第1ラウンドのイベントサイクルは、まずマクロタスクを実行し、メインscript、new Promiseが直ちに実行し、出力3、pというnew Promise操作を実行し、出力7、set Timeoutを発見し、次のタスクキュー(Event Quene)、pのthenにコールバック関数を入れ、一旦then 1と命名し、マイクロタスクキューに入れます.consone.log(4)を実行し、4を出力し、マクロタスクの実行が終了します.
また、マイクロタスクを実行し、then 1を実行し、1を出力し、then 2を実行し、3を出力する.
第1ラウンドのイベントサイクルが終了し、第2ラウンドの実行が開始されます.第二ラウンドのイベントサイクルはまずマクロタスクの中の、つまりsetTimeoutのフィードバックを実行して、出力5.resove(6)は有効になりません.pのPromise状態が変化したら、もう変化しません.
実行結果:
// => 3
// => 7
// => 4
// => 1
// => 2
// => 5
問題3
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})

console.log('promise1', promise1)
console.log('promise2', promise2)

setTimeout(() => {
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)
実行結果:
promise1 Promise {}
promise2 Promise {}
Uncaught (in promise) Error: error!!!
    at 
promise1 Promise {: "success"}
promise2 Promise {: Error: error!!!
    at }
プロミスには3つの状態があります.状態の変化は、pending->fulfilledまたはpending->rejectでしかなく、状態が変われば、二度と変えられません.上記promise 2はプロミゼ1ではなく、新たなプロミスの例を返します.
問題四
const promise = new Promise((resolve, reject) => {
  resolve('success1')
  reject('error')
  resolve('success2')
})

promise
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })
コンストラクタの中のresoveまたはrejectは初めて有効に実行されます.何度もコールしても効果がないです.呼応コード2の結論:promise状態が変われば、二度と変更できないです.
実行結果:
then: success1
問題5
Promise.resolve(1)
  .then((res) => {
    console.log(res)
    return 2
  })
  .catch((err) => {
    return 3
  })
  .then((res) => {
    console.log(res)
  })
promiseはチェーンで呼び出すことができます.チェーンコールといえば、私たちはよくreturn thisによって実現すると思いますが、Promiseはこのように実現したのではありません.プロミスは毎回呼び出します.thenまたはcatchは新しいプロミスを返します.チェーンコールを実現しました.
実行結果:
1
2
問題6
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})

const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})
解析:promiseの.thenまたは.catchは何度も呼び出すことができますが、ここではPromise構造関数は一回だけ実行します.あるいはpromiseの内部状態が変化し、値が一つあると、その後の呼び出し毎に、thenまたは.catchがその値を直接取得する.
実行結果:
once
success 1005
success 1007
問題7
Promise.resolve()
  .then(() => {
    return new Error('error!!!')
  })
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })
解析:thenまたは.catchの中のreturnの一つのerrorオブジェクトは間違っていないので、後続のcatchに捕獲されないので、その一つに変更する必要があります.
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
いずれかの非プロミスに戻る値はプロミスオブジェクト、すなわちreturn new Error('error!!!!!!')と同じです.
実行結果:
then:  Error: error!!!
    at 
問題8
const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)
解析:thenまたは.catchの値はpromise自体ではなく、死のサイクルを引き起こします.類似点:
process.nextTick(function tick () {
  console.log('tick')
  process.nextTick(tick)
})
実行結果:
TypeError: Chaining cycle detected for promise #
9題
Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)
解析:thenまたは.catchのパラメータは関数を期待しています.非関数が入ると、値が透過します.
実行結果:
1
問題10
Promise.resolve()
  .then(function success (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .catch(function fail2 (e) {
    console.error('fail2: ', e)
  })
thenは二つのパラメータを受信できます.一つ目は成功した関数、二つ目はエラー処理の関数です.catchは.thenの2番目のパラメータの簡単な書き方ですが、使い方には注意が必要です.thenの2番目の処理エラーの関数は最初の処理が成功した関数から投げられたエラーを捕まえられません.後のcatchは前のエラーを捕まえられます.もちろん以下のコードもいいです.
Promise.resolve()
  .then(function success1 (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .then(function success2 (res) {
  }, function fail2 (e) {
    console.error('fail2: ', e)
  })
実行結果:
fail2:  Error: error
    at success ()
タイトル11
process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')
解析:process.nextTickとpromise.thenはすべてmicrotaskに属し、setImmediteはmacrotaskに属し、イベントサイクルのcheck段階で実行されます.イベントサイクルの各段階(macrotask)の間でmicrotaskが行われます.イベントサイクルの開始はまずmicrotaskが行われます.
実行結果:
end
nextTick
then
setImmediate
筆記試験問題
上の問題は基礎的すぎて、挑戦性がないですか?本物を注文します.
プログラミング問題
赤信号は3秒に一回、青信号は1秒に一回、黄色灯は2秒に一回点灯します.Promiseを使って、三つのランプを交互に点灯させるにはどうすればいいですか?(海康威視のペン問題)
function red(){
    console.log('red');
}
function green(){
    console.log('green');
}
function yellow(){
    console.log('yellow');
}
まずテーマを見てください.テーマは赤信号が終わったら、緑のランプが点灯します.黄色のランプが点灯してから、赤信号が点灯します.だから、Promiseでどうやって実現しますか?
言い換えれば、赤信号が点灯したら、2秒後に青信号を点灯し、青信号が点灯したら1 s後に黄色ランプを点灯し、3 s後に赤信号を点灯すると約束します.これは明らかにPromiseチェーン式の呼び出しです.ここを見たら、心の中に考えがあるかもしれません.私たちはそれぞれの点灯動作をthen()方法に書いて、同時に新しいPromiseに戻ります.その状態をpendingからfulfilledに設定し、次のランプが点灯するようにします.
function red() {
  console.log('red');
}

function green() {
  console.log('green');
}

function yellow() {
  console.log('yellow');
}


let myLight = (timer, cb) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      cb();
      resolve();
    }, timer);
  });
};


let myStep = () => {
  Promise.resolve().then(() => {
    return myLight(3000, red);
  }).then(() => {
    return myLight(2000, green);
  }).then(()=>{
    return myLight(1000, yellow);
  }).then(()=>{
    myStep();
  })
};
myStep();

// output:
// => red
// => green
// => yellow
// => red
// => green
// => yellow
// => red
プログラミング2
mergPromise関数を実現して、転送された配列を順番に順次実行してください.そして戻ったデータを順番に配列dataに入れます.
const timeout = ms => new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve();
    }, ms);
});

const ajax1 = () => timeout(2000).then(() => {
    console.log('1');
    return 1;
});

const ajax2 = () => timeout(1000).then(() => {
    console.log('2');
    return 2;
});

const ajax3 = () => timeout(2000).then(() => {
    console.log('3');
    return 3;
});

const mergePromise = ajaxArray => {
    //          

};

mergePromise([ajax1, ajax2, ajax3]).then(data => {
    console.log('done');
    console.log(data); // data   [1, 2, 3]
});

//       
// 1
// 2
// 3
// done
// [1, 2, 3]
解析:このテーマはPromiseで非同期プロセスを制御することを考察します.まずajax 1、ajax 2、ajax 3は関数です.これらの関数を実行したらPromiseに戻ります.テーマの要求によって順番にこの三つの関数を実行すればいいです.そして結果をdataに入れます.
答え:
const mergePromise = ajaxArray => {
  //          
  //               
  var data = [];

  // Promise.resolve         ,      resolved    Promise   。
  var sequence = Promise.resolve();

  ajaxArray.forEach(item => {
    //      then               ,
    //      then                   ,
    //         data  ,    data   。
    sequence = sequence.then(item).then(res => {
      data.push(res);
      return data;
    });
  });

//      ,     Promise,    sequence,    [[PromiseValue]]     data,
//   data(              )       ,        then    。
  return sequence;
};
プログラミング問題三
既存の8つのピクチャリソースのurlは、すでに配列urlsに格納されており、もう一つの関数function loadingがあります.urlリンクを入力して、Promiseに戻ります.このPromiseは、画像のダウンロードが完了したときに、rejectをダウンロードしました.要求:いつでも同時にダウンロードするリンクの数は3つを超えてはいけません.この需要を実現するためにコードを書いてください.できるだけ速くすべての画像をダウンロードしてください.
var urls = ['https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg', 'https://www.kkkk1000.com/images/getImgData/gray.gif', 'https://www.kkkk1000.com/images/getImgData/Particle.gif', 'https://www.kkkk1000.com/images/getImgData/arithmetic.png', 'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif', 'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg', 'https://www.kkkk1000.com/images/getImgData/arithmetic.gif', 'https://www.kkkk1000.com/images/wxQrCode2.png'];

function loadImg(url) {
    return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = () => {
            console.log('        ');
            resolve();
        }
        img.onerror = reject;
        img.src = url;
    })
};
問題を解析するには、まず3枚の画像を同時に要求し、1枚の画像のロードが完了すると、また1枚の画像の要求を開始し、同時に3つの画像を保持させ、ロードが必要な画像まで全部要求を開始するという意味です.
Promiseで実現すると、まず3つの画像リソースを同時に要求し、これにより3つのPromiseが得られ、1つの配列promisesを構成し、そしてPromise.raceを呼び出して、一番速い状態のPromiseに戻ります.その後、プロミセからこのPromiseオブジェクトを削除し、新たなPromiseを加えて、全部のurlが取り消されるまで、最後にPromise.allを使って、一回の配列を処理します.promisesの中で状態を変えていないPromiseを処理します.
function limitLoad(urls, handler, limit) {
  //         
    const sequence = […urls];

  let promises = [];

  //        
  promises = sequence.splice(0, limit).map((url, index) => {
    //       index      promises    ,    Promise.race            
    return handler(url).then(() => {
      return index;
    });
  });

  //       reduce            
  return sequence.reduce((last, url, currentIndex) => {
    return last.then(() => {
      //           Promise
      return Promise.race(promises)
    }).catch(err => {
      //     catch          then        
      //                
      console.error(err)
    }).then((res) => {
      //     Promise            Promise
      promises[res] = handler(sequence[currentIndex]).then(() => {
        return res
      });
    })
  }, Promise.resolve()).then(() => {
    return Promise.all(promises)
  })

}

limitLoad(urls, loadImg, 3);

/*
   limitLoad         Promise,             ,        

limitLoad(urls, loadImg, 3).then(() => {
    console.log('        ');
}).catch(err => {
    console.error(err);
})
*/
プログラミング問題4
パッケージに非同期で画像をロードする方法解析:これは難しくないです.
function loadImageAsync(url) {
    return new Promise(function(resolve,reject) {
        var image = new Image();
        image.onload = function() {
            resolve(image) 
        };
        image.onerror = function() {
            reject(new Error('Could not load image at' + url));
        };
        image.src = url;
     });
}
完結する
この部分の問題はネットで集めた練習問題です.何かのプログラミング問題は自分で初めて作ったのもそんなにうまくないと思いますが、仕上げはとても勉強になりました.Promiseの特性とPromiseの使い方に対する理解が深まりました.ですから、Promiseは本当に勉強します.やはり具体的なシーンと合わせて、実際に開発して運用します.
Promise機能は簡単に見えるが、整理してみるとPromiseの内容は確かに多いです.自分は一日中をかけて調べたり、勉強したり、コードを理解したり、走ったりして、Promiseのノートを整理しています.
読んでくれてありがとうございます
推荐阅覧:【テーマ:JavaScript进階の道】JavaScriptの深度理解クローズドES 6尾呼出と最後再帰Git常用命令小结JavaScriptのcall()理解JavaScriptの対象属性
私はCloudyです.若い先端で城を攻める獅子です.専門研究を愛し、技術を愛し、分かち合います.
個人のノート、整理は簡単ではありませんて、読んで、点の賛美と収集に感謝します.
文章には何か問題があります.ご指摘ください.先端の問題も一緒に交流してください.