js非同期入門から放棄(実践編)—よくある書き方&面接問題解析


前文


このシリーズの前のいくつかの文章はそれぞれ異なるいくつかの非同期案の原理を解析し、本文はいくつかの実際のシーンといくつかのよくある面接問題を紹介する.(蓄積が足りないので、後で補足したいと思います)

本文


プロセススケジューリング


プロセススケジューリングでは、最も一般的なのは、リレーと同時(またはシリアルと並列)の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()

    ここで、concurrentScheduleByAsyncserialScheduleByAsyncの違いを判別するには、同じ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)を直接見ることができる.

    小結


    この文章は主にこのシリーズに簡単な終わりを作って、単独で純粋で非同期の問題の難点も実は多くなくて、怠け者を盗んで、後で考えてから補充します.
    书き方が悪い/间违いがある/表现がはっきりしていないと感じたら、助けがあれば、賛美とコレクションを歓迎します.転载は同意を得てから出典を明らかにしてください.问题があれば私信交流も歓迎します.ホームページにメールアドレスがあります.作者が大変だと思ったら、赏賛も歓迎します.