js非同期入門から放棄(実践編)—よくある書き方&面接問題解析
6016 ワード
前文
このシリーズの前のいくつかの文章はそれぞれ異なるいくつかの非同期案の原理を解析し、本文はいくつかの実際のシーンといくつかのよくある面接問題を紹介する.(蓄積が足りないので、後で補足したいと思います)
本文
プロセススケジューリング
プロセススケジューリングでは、最も一般的なのは、リレーと同時(またはシリアルと並列)の2つのタイプであり、日常的な仕事でよく見られます.次に、実際のシーンについて説明します.
1.前のステップの結果に依存する一連の非同期動作をシリアルで実行
シリアル実行の鍵は、各非同期タスクを前の非同期タスクのコールバック関数に配置して実行することです.
プロセススケジューリング
プロセススケジューリングでは、最も一般的なのは、リレーと同時(またはシリアルと並列)の2つのタイプであり、日常的な仕事でよく見られます.次に、実際のシーンについて説明します.
1.前のステップの結果に依存する一連の非同期動作をシリアルで実行
シリアル実行の鍵は、各非同期タスクを前の非同期タスクのコールバック関数に配置して実行することです.
// 5
// getAnimation i promose
const getAnimation = (i) => new Promise((resolve, reject) => {
setTimeout(()=>{
// true false
const isSuccess = Math.random() > 0.5
console.log(` ${i} `)
if(isSuccess){
return resolve(isSuccess)
}
return reject(isSuccess)
},1000)
})
// 1.promise
const serialScheduleByPromise = () => {
let p = Promise.resolve(true)
const tasks = []
for(let i=0;i < 5; i++){
p = p.then(isSuccess=>{
if(isSuccess){
return getAnimation(i+1)
}
}).catch((err)=>{
return console.log(` `)
})
}
}
serialScheduleByPromise()
// 2.async/await
const serialScheduleByAsync = async () => {
try{
for(let i=0;i < 5; i++){
await getAnimation(i+1)
}}catch(e){
console.log(` `)
}
}
serialScheduleByAsync()
async/await
の文法は単独では解析されていないが,本質は前編で紹介した自動アクチュエータ付きgenerator
であるため,asyncの書き方コードがより簡潔で論理がより明確で,可読性がより強いことは言うまでもない.2.すべての非同期動作を並列に実行し、すべての要求が完了するまで、読み出し要求の順序で結果を出力する
シーン:5個のデータを同時に読み出し(便宜上1~5)、実際の読み出し順で結果を出す
const getDataById = (i) => new Promise((resolve, reject) => {
// ,
const delay = Math.floor(Math.random() * Math.floor(3000)) // 0,1000,2000
setTimeout(()=>{
return resolve(i)
}, delay)
})
// 1.promise
const concurrentScheduleByPromise = ()=>{
const promises = []
const result = []
for(let i = 0;i < 5;i++){
promises[i] = getDataById(i+1)
promises[i].then(i=>{
result.push(i)
})
}
Promise.all(promises).then(()=>{
result.forEach(id=>{
console.log(id)
})
})
}
concurrentScheduleByPromise()
// async/await
const concurrentScheduleByAsync = () => {
for(let i = 0 ;i < 5; i++){
let task = async function (){
console.log(await getDataById(i+1))
}
task()
}
}
concurrentScheduleByAsync()
ここで、
concurrentScheduleByAsync
とserialScheduleByAsync
の違いを判別するには、同じasync
関数の内部にあるawait
が順次実行されることに注意してください.プロセススケジューリングでよく見られるエラーの1つは、「シリアルに見える」書き方です.この例を感じてみてください.
const getPromise = (name) =>new Promise(resolve=>{
setTimeout(()=>{
console.log(name)
resolve(name)
},1000)
})
//
Promise.resolve().then(getPromise('1a')).then(getPromise('1b')).then(getPromise('1c'))
Promise.resolve().then(()=>getPromise('2a')).then(()=>getPromise('2b')).then(()=>getPromise('2c'))
Promise.resolve().then(getPromise('3a').then(getPromise('3b').then(getPromise('3c'))))
Promise.resolve().then(()=>getPromise('4a').then(()=>getPromise('4b').then(()=>getPromise('4c'))))
出力順序の判別
このような問題は一般的に面接問題に出ている.
1.基本-異なるタスク・タイプを区別
console.log(1)
new Promise(resolve => {
console.log(2)
setTimeout(() => {
console.log(10)
}, 10)
resolve()
console.log(3)
}).then(() => {
console.log(5)
})
setTimeout(() => {
console.log(7)
Promise.resolve().then(() => {
console.log(9)
})
console.log(8)
})
Promise.resolve().then(() => {
console.log(6)
})
console.log(4)
// 1 2 3 4 5 6 7 8 9 10
2.複雑-ブラウザrenderに追加
outer
inner
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
console.log('mutate');
}).observe(outer, {
attributes: true
});
// Here's a click listener…
function onClick() {
console.log('click');
setTimeout(function () {
console.log('timeout');
}, 0);
Promise.resolve().then(function () {
console.log('promise');
});
outer.setAttribute('data-random', Math.random());
}
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
// innner.click() js click
このような問題は実質的に非同期タスクキュータイプを判別することであり,詳細と解析はjs非同期の入門から放棄(3)−非同期タスクキュー(task queues)を直接見ることができる.