js 防抖節流,同步異步,promise

防抖

   防抖  指觸發事件後在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。
  //非立即執行
        let box = document.getElementById('box')
        let num = 1;
        function add() {
            box.innerHTML = num++
        }
        function debounce(fn,time) {
            //這個作用域不銷燬
            //保護保存
             let timer = null;
             return function(){
                 clearTimeout(timer)
                 timer = setTimeout(()=>{
                     fn.call(this)
                 },time)
             }
         }
         box.onmousemove = debounce(add,1000)
        // onmousemove綁定的真正的函數是debounce返回值


        //立即執行:如果n秒內不再觸發事件,函數纔會執行;
        //防止惡意觸發頻繁點擊,n秒觸發一次
         function debounce(fn,time) {
             let timer = null;
             return function() {
                 clearTimeout(timer);
                 let now = !timer
                 timer = setTimeout(()=>{
                     timer = null;
                 },time)
                 if(now){
                     fn.call(this)
                 }
             }
         }
         box.onmousemove = debounce(add,1000)



        //合併版
        function debounce(fn, time, immediate) {
            let timer
            return function () {
                if (immediate) {
                    clearTimeout(timer);
                    let now = !timer;
                    timer = setTimeout(() => {
                        timer = null;
                    }, time)
                    if (now) {
                        fn.call(this)
                    };
                } else {
                    clearTimeout(timer);
                    timer = setTimeout(() => {
                        fn.call(this)
                    }, time);
                }
            }

        }
        box.onmousemove = debounce(add, 1000, true)



節流

 節流  指連續觸發事件但是在 n 秒中只執行一次函數。節流會稀釋函數的執行頻率。
      // onmousemove :當鼠標在元素上滑動觸發
        // onscroll:滾動條
        // onmouseover: 移入
        // onmouseout: 移出
        //時間戳版  
        function throttle(fn,time){
             let previous = 0;
             return function() {
                 let now = Date.now();
                 if(now - previous >= time){
                     fn.call(this);
                     previous = now;
                 }
             }
         }
         box.onmousemove = throttle(add,2000);
        //定時器版
         function throttle(fn, time) {
             let timer;
             return function () {
                 if (!timer) {
                     timer = setTimeout(() => {
                         timer = null
                         fn.call(this)
                     },time)
                 }
		     }
        }
        box.onmousemove = throttle(add, 2000);


        //合併版
        function throttle(fn, time, type) {
            if (type === 1) {
                var previous = 0;
            } else {
                var timer;
            }
            return function () {
                if (type === 1) {
                    let now = Date.now();
                    if (now - previous >= time) {
                        fn.call(this);
                        previous = now;
                    }
                } else if (type === 2) {
                    if (!timer) {
                        timer = setTimeout(() => {
                            timer = null;
                            fn.call(this);
                        }, time);
                    }
                }
            }
        }
        box.onmousemove = throttle(add, 2000, 1);

定時器同異步

  時間循環流程
	  執行棧   等待棧
	  調用棧中的同步任務都執行完畢,棧內被清空了,就代表主線程空閒了,這個時候就會去任務隊列中按照順序讀取一個任務放入到棧中執行。每次棧內被清空,都會去讀取任務隊列有沒有任務,有就讀取執行,一直循環讀取-執行的操作,就形成了事件循環。
	     當瀏覽器解析JS時,會先把所有同步代碼執行完,然後再執行異步
	 js是單線程   js同一時間只能執行一行代碼
	 瀏覽器是多線程
	 線程是一個小的進程
     異步  :定時器  ajax  事件(onload,onclick,promise,async,await)
	    1.如果兩個定時器都在for循環的上面,誰的時間小,先執行誰,如果時間相同 按順序執行
	    2.當同步代碼執行完畢,會對異步任務進行比較,誰先到達執行時間,先執行誰
	 當js運行時,分爲主任務隊列和等待任務隊列,主任務都是同步的,異步是等待任務隊列,只有主任務隊列執行完畢,纔會執行等待任務隊列

    js將請求數據這個任務交給了瀏覽器,瀏覽器去向服務器請求數據,服務器把數據返回給瀏覽器
 setInterval  每隔多長時間執行一次
      setTimeout    到了一定時間執行一次
      瀏覽器最小識別時間:谷歌 5-6ms  火狐 10-12  IE 13-15
      setTimeout  當代碼運行到setTimeout 這裏時,瀏覽器會給當前定時器記錄一個開始時間
      //定時器的返回值是代表當前頁面中第幾個定時器  

      function fn(){
          var a =setTimeout(function(){},1000)
          console.log(a); //2
            
      }
      var timer = setTimeout(function(a,b){
        console.log(a,b);//1 2
        return 100

      },2000,1,2) //1和2傳給了function函數
      fn();
      console.log(timer);//1

    計算for循環的時間
      var cur = Date.now();
      for(var i = 0;i<10000000;i++){

      }
      console.log(Date.now()-cur);
      

 
    setTimeout(function(){
        //這個函數是異步的
        console.log(100);       //5
    },20)
    console.log(300);          //1
    setTimeout(function(){
        //這個函數是異步的
        console.log(400);       //4
    },10)
    for(var i=0;i<1000000;i++){
        //for 同步
    }
    console.log(200);           //2
    window.onload = function(){
        setTimeout(function(){
        //這個函數是異步的
        console.log(500);           //7
    },20)
    console.log(600);             //3
    setTimeout(function(){
        //這個函數是異步的
        console.log(700);           //6
    },10)
    for(var i=0;i<1000000;i++){
        //for 同步
    }
    console.log(800);              //4
    }
    //輸出 300 200 100   
    //時間一樣 異步一次走  不一樣 誰快誰先走

多方向運動公式

  //當點擊盒子的時候,讓盒子橫向運動500px,縱向運動300px,width:200px;height:200px;
        function linear(t, b, c, d) {
            // t:運動過的時間
            // b:起始位置
            // c:要運動總距離
            // d:需要的總時間
            //此時此刻位置    c/d*t+b
            return c / d * t + b
        }
        let box = document.getElementById('box');
        let target = {
            left: 500,
            top: 300,
            width: 200,
            height: 200
        }
        let curStart = getComputedStyle(box)
        let begin = {
            left: parseFloat(curStart.left),
            top: parseFloat(curStart.top),
            width: parseFloat(curStart.width),
            height: parseFloat(curStart.height),
        };
        let duration = 3000;
        let change = {};
        let timer = null;
        //計算出變化的值
        for (let key in target) {
            change[key] = target[key] - begin[key]
        }
        box.onclick = function () {
            clearInterval(timer)
            let t = 0
            timer = setInterval(() => {
                t += 20;
                for (let key in change) {
                    let cur = linear(t, begin[key], change[key], duration);
                    box.style[key] = cur + 'px';
                }
                if (t >= duration) {
                    clearInterval(timer)
                    timer = setInterval(() => {
                        t -= 20;
                        for (let key in change) {
                            let cur = linear(t, begin[key], change[key], duration);
                            box.style[key] = cur + 'px';
                            if(t<=0){{
                                clearInterval(timer)
                            }}
                        }
                        
                    }, 20);
                }
            }, 20);
        }

promise

 Promise 是ES6中新增的一個類,專門用來解決異步回調地獄的問題,將異步代碼同步顯示出來;
     promise  三個狀態 : Pending     fulfilled  rejected
    改變狀態有兩種可能  pending-->fulfilled  pending--> rejected
 
        $.ajax({
            url:"time/ww",
            success:function(data){
                $.ajax({
                    當第一個請求成功以後再發第二個
                    success:function(){
                        $.ajax({
                        })
                    }
                })
            }
        })
        axios  fetch 
  
        let p = new Promise(function(resolve,reject){
            //setTimeout(()=>{
                resolve();  // 調用resolve代表執then中的第一個回調,resolve代表的是成功態
                // 調用reject ,就代表執行then的的第二個回調;,失敗態
                reject();
            //},1000)
        }).then(function(){
            console.log(1);
        },function(){
            console.log(2);
        }).then(function(){

        },function(){
            
        })
    //   setTimeout(function(){
    //     console.log(p);
    //   },2000)
        
        
        
        
promise的回調函數 是同步的 then對應的函數是異步的
    定時器是等待任務    又分爲宏任務和微任務,當執行棧主任務隊列執行完,要執行等待任務,在執行等待任務時,先執行微任務,後執行宏任務
    then  微任務    定時器  宏任務
setTimeout(function () {
                    console.log(500);
        
                }, 0)
                console.log(100);
        
                let p = new Promise(function (resolve, reject) {
                    console.log(300);
        
                    resolve();
                    console.log(200);
        
                });
                p.then(function () {
                    console.log(400);
        
                })
        
                console.log(600); */
        //100,300,200,600,400,500 
Promise.all()
	  Promise.all()  私有屬性   用於多個實例 返回一個新Promise實例
     只有當p1,,p2,p3狀態全部爲filfulled,那麼新實例纔是成功的
     只要有一個rejected  就是失敗
let p1 = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(100)
            },3000)
        })
        let p2 = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(200)
            },2000)
        })
        let p3 = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(300)
            },4000)
        })
        let p = Promise.all([p1,p2,p3])
        p.then(function(data){
            //會將所有成功數據組裝成一個新數組,傳遞給這個回調函數
            console.log(data);
            
        }).catch(function(data){
            //只要遇到一個失敗,就將失敗的值傳遞給這個回調
            console.log(data);
            
        })
Promise.prototype.catch()
  let p = new Promise(function(resolve,reject){
            resolve()
        })
        p.then(function(){
            console.log(1);
            throw new Error() //如果在then中拋出異常,則會執行下面catch
            //如果then中代碼有異常,也會拋出錯誤
            //只有then鏈中有一個異常,就會執行最後的catch,只要在then中有失敗的回調,就不再執行最後的catch了
            //catch 同步
        }).then(function(){
            console.log(5);
            
        }).catch(function(){
            console.log(2);
            
        })
        
Promise.prototype.finally()
finally方法用於指定不管 Promise 對象最後狀態如何,都會執行的操作
  try{
          console.log(2);
          
      }catch(e){
        console.log(1);
        
      }finally{
          console.log(3);
          
      }
       //2   3 

    //   finally 異步
    let p = new Promise(function(resolve,reject){
            resolve()
        })
        p.then(function(){
            console.log(1);
          
        }).then(function(){
            console.log(5);
            
        }).catch(function(){
            console.log(2);

        }).finally(function(){
            console.log(1000);
            // // 這是會等到promise實例狀態改變以後會觸發的回調,是一個異步的;
        })
        console.log(999);
        //999 1  5  1000
Promise.race()
	Promise.race()方法同樣是將多個 Promise 實例,包裝成一個新的 Promise 實例。
	只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。
  let p1 = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(100)
            },3000)
        })
        let p2 = new Promise(function(resolve,reject){
            setTimeout(function(){
                reject(200)
            },5000)
        })
        let p3 = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(300)
            },4000)
        })
        let p = Promise.race([p1,p2,p3])
        p.then(function(data){
            console.log('成功');
            
        }).catch(function(data){
            console.log('失敗');
            
        })
        
        
Promise.resolve:
	將一個對象轉成一個promise的實例;返回值可以調用then方法
   Promise.resolve("foo").then(function () {

        })
        new Promise(function (resolve, reject) {
            resolve("foo")
        });

        Promise.reject("foo").then(function () {

        })
        new Promise(function (resolve, reject) {
            reject("foo")
        });
        let p = Promise.resolve();
        p.then(function () {

        })

        let a = {
            then: function () {

            }
        }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章