es6常用功能與異步詳解(JS高級面試題)


callback hell方法的使用

可讀性不友好

function loadImg(src,callback,fail){
    var img = document.createElement('img');
    img.onload = function(){
        callback(img);
    }
    img.onerror = function(){
        fail();
    }
    img.src = src;
}
var src = "https://www.baidu.com/img/baidu_jgylogo3.gif";

loadImg(src,function(img){
    console.log('img width',img.width)
},function(){
    console.log('faild')
})

用promise 去改造

用多個.then去分批處理

function loadImg(src){
    return new Promise(function(resolve,reject){
        var img = document.createElement('img');
        img.onload = function(){
            resolve(img);
        }
        img.onerror = function(){
            reject();
        }
        img.src = src;
    })
}
var src="https://www.baidu.com/img/baidu_jgylogo3.gif";
var result = loadImg(src);
result.then(function(img){
    console.log('img width',img.width)
},function(){
    console.log('faild')
})
result.then(function(img){
    console.log('img height',img.height)
})

問題解答:

  1. new promise實例,而且要傳入return
  2. new promise時要傳入函數,函數有resolve reject函數
  3. 成功時執行resolve()失敗時執行reject()
  4. .then監聽結果

ES6常用功能

  1. let 定義變量,可以重新賦值
  2. const 定義常量,不可以重新賦值
  3. 多行字符串/模板變量
  4. 解構賦值(詳情見es6)
  5. 塊級作用域(很大的改動)
  6. 函數默認參數
  7. 箭頭函數

塊級作用域

<!-- 在js里面 -->
var obj = {a:100,b:200}
for (var key in obj) {
    console.log(key,'for in')
}
console.log(key)  // 100,200

<!-- 在es6 -->
var obj = {a:100,b:200}
for (let key in obj) {
    console.log(key,'for in')
}
console.log(key); // undefine

箭頭函數改變this指向的問題

<!-- 用箭頭函數,指向本身函數對象 -->
function fn(){
    console.log('real',this); // {a:100}

    var arr = [1,2,3];
    arr.map(item=>{
        console.log(this); // {a:100}
    })
}
fn.call({a:100}); // call是強制讓fn函數對象指向{a:100}

<!-- 不用箭頭函數,this指向window -->
function fn(){
    console.log('real',this); // {a:100}

    var arr = [1,2,3];
    arr.map(function(item){
        console.log(this); // window;
    })
}
fn.call({a:100});

原型

描述一下zepto是如何使用原型 描述一下jquery如何使用原型 再結合自己的項目經驗,說一個自己開發的列子

$p.css('color','red'); // css是原型方法
$p.html(); // html是原型方法

原型如何體現他的擴展性

異步

問題:

一. 什么是單線程,和異步有什么關系
  1. 單線程只有一個線程,同一時間只能做一件事情
var i,sum = 0;
for(i=0;i<100000;i++){
    sum+=i;
}
console.log(sum);

<!-- alert不處理,js執行和dom渲染暫時卡頓 -->
console.log(1);
alert('hello');
console.log(2);
  1. 用單線程的原因-避免DOM渲染的沖突

    1. 瀏覽器需要渲染DOM

    2. js可以修改DOM結構

    3. JS執行的時候,瀏覽器DOM渲染會暫停

    4. 兩段JS也不能同時執行(都修改DOM就沖突了)

    5. webworder支持多線程,但是不能訪問DOM

  2. 單線程的解決單線程方案-異步

    console.log(100)
    setTimeout(function(){
        console.log(200);
    },1000)
    console.log(300);
    console.log(400);
    // 100
    // 300
    // 400
    // 200  一秒后執行
console.log(100)
$.ajax({
    url:'XXXX',
    success:function(res){
        console.log(res) // 最后執行
    }
});
console.log(300)
cobsole.log(400)

異步的問題:

問題一:沒有按照書寫的方式執行,可讀性差

問題二:callback中不容易模塊化(setTimeout和ajax里面的函數)

二. 什么是event-loop 異步的解決方案。
  1. 事件輪詢,js實現異步的具體解決方案
  2. 同步代碼,直接執行
  3. 異步函數先放在異步隊列中;有setTimeout等待時間過后,才放入異步隊列中。ajax執行完畢過后放入異步隊列
  4. 待同步函數執行完畢,輪詢執行異步隊列的函數

回答點:

  1. 什么是異步隊列,何時被放入異步隊列
  2. 輪詢的過程。
三. 是否用過jquery的deferred

問題解答:

1. 可以拿jquery1.5 對ajax的改變舉例

2. 說明如何簡單的封裝、使用deferred,說出它的好處

3. 說明promise和deferred的區別

jQuery1.5的變化——1.5之前

var ajax = $.ajax({
    url:'./data.json',
    success:function(){
        console.log('success 1');
        console.log('success 2');
        console.log('success 3');
    },
    error:function(){
        console.log('error');
    }
})

jQuery1.5的變化——1.5之后 這樣寫的好處:

  1. 這樣對修改封閉,對擴展開放,
  2. 增加一個函數,不用再修改原來的函數
  3. 多人開發,一人維護一個函數。
  4. 測試也只測試新的函數。
  5. 對代碼管理和維護有好處的
// 每一個方法都會執行
var ajax = $.ajax('data.json');
ajax.done(function(){
    console.log('success 1');  
}).fail(function(){
  console.log('fail 1');  
}).done(function(){
    console.log('success 2');  
}).fail(function(){
  console.log('fail 2');  
}).done(function(){
    console.log('success 3');  
}).fail(function(){
  console.log('fail 3');  
})

<!-- 與promise很相近了 -->
var ajax = $.ajax('data.json')
ajax.then(function(){
   console.log('success 1'); 
},function(){
    console.log('error 1');
}).then(function(){
   console.log('success 2'); 
},function(){
    console.log('error 2');
})
  1. 無法改變js異步和單線程的本質
  2. 只能從寫法上杜絕callback這種形式
  3. 它是一種語法糖形式,但是解耦了代碼
  4. 很好的體現:開放封閉原則
  5. 減少了回歸測試的成本。多人開發方便。

使用jquery deferred舉例:

var wait = function(){
    var task = function(){
        console.log('執行完成');
    }
    setTimeout(task,20000)
}
wait();
function waitHandle(){
    // 定義 
    var dtd = $.Deferred();
    
    var wait = function(dtd){
    
        var task = function(){
            console.log('執行完畢');
            // 成功
            dtd.resolve()
            // 失敗
            // dtd.reject()
        }
        setTimeout(task,2000);
        
        // wait返回
        return dtd;
    }
    
    // 最終返回
    return wait(dtd);
}

var w = waitHandle();
w.then(function(){
    console.log('ok 1');
},function(){
    console.log('err 1');
})
w.then(function(){
    console.log('ok 2');
},function(){
    console.log('err 2');
})
w.then(function(){
    console.log('ok 3');
},function(){
    console.log('err 3');
})

w.reject();  //  不會報錯


// 開放封閉原則!!!

總結: dtd的API可分成兩類,用意不同

第一類:dtd.reolve  dtd.reject  主動觸發

第二類:dtd.then  dtd.done  dtd.fail  被動監聽

初步引入promise概念,是 jquery deferred 引入過來的

promise和jquery deferred的區別:

promise對象只能被動監聽,不能主動修改,所以在w.reject()會報錯。

function waitHandle(){
    // 定義 
    var dtd = $.Deferred();
    
    var wait = function(dtd){
    
        var task = function(){
            console.log('執行完畢');
            // 成功
            dtd.resolve()
            // 失敗
            // dtd.reject()
        }
        setTimeout(task,2000);
        
        // wait返回
        return dtd.promise(); // 這里返回的是promise對象
    }
    
    // 最終返回
    return wait(dtd);
}
var w = waitHandle();
$.when(w).then(function(){
    console.log('ok 1');
},function(){
    console.log('err 1');
}).then(function(){
    console.log('ok 2');
},function(){
    console.log('err 2');
})

w.reject();  // 這里就會直接報錯。

四. promise的基本使用和原理

基本語法回顧

1. 異常捕獲

function loadImg(src){
    return new Promise(resolve,reject){
        var img = document.createElement('img');
        img.onload = function(){
            resolve(img);
        }
        img.onerror = function(){
            reject('圖片加載失敗');
        }
        img.src=  src;
    }
}

var src="https://wwww.img.address";
var result = loadimg(src);
// 規定:then只接受一個成功的參數,最后統一用catch來捕獲錯誤
result.then(function(img){
    console.log(1,img.width);
    return img;
}).then(function(img){
    console.log(2,img.width);
}).catch(function(ex){
    // 統一捕獲異常,也會捕獲到reject方法
    console.log(ex);
})

2. 多個串聯

// 場景:希望加載完第一個,再加載第二個
var src1 = 'img.address';
var result1 = loadImg(src1);
var src2 = 'img.address';
var result2 = loadImg(src2);

result1.then(function(img1){
    console.log('加載第一章圖片',img1.width);
    return result2  // 重要!!!
}).then(function(img2){
    console.log('加載第二章圖片',img2.width);  
}).catch(function(ex){
    console.log(ex);
})

3. promise.all和promise.race

// Promise.all接收一個promise對象的數組
// 待全部完成之后,統一執行success
Promise.all([result1,result2]).then(datas=>{
    // 接收到的datas是一個數組,依次包含了多個promise返回的內容
    console.log(datas[0]);
    console.log(datas[1]);
})

// Promise.race 接收一個包含多個promise對象的數組
// 只要有一個完成,就執行success
Promise.race([result1,result2]).then(data=>{
    // data 是最先執行完成的 promise對象的返回值
    console.log(datas);
})

4. promise標准

關於“標准”的閑談,標准很重要

    任何技術推廣使用都需要一套標准來支撐
    如 html js css http等,無規則不成方圓
    任何不符合標准的東西,終將會被用戶拋棄

狀態變化

    三種狀態:pending fulfilled rejected
    初始狀態pending
    pending 變成fulfilled,或者pending變為rejected
    狀態不可逆

then

promise 實例必須實現then這個方法
then()必須可以接收兩個函數作參數
then()返回的必須是一個promise實例

問題解答總結:

1. 基本語法復習
2. 如何異常捕獲(error和reject都要考慮)
3. 多個串聯-鏈式執行的好處
4. promise.all和promise.race
5. promise標准-狀態變化,then函數
五. 介紹一下 async/await

是es7體驗中的。

then只是將callback拆分了

async/await是最直接的同步寫法

const load = async function(){
    const result1 = await loadImg(src1);
    console.log(result1);
    const result2 = await loadImg(src1);
    console.log(result2);
}
load()

語法(和promise的區別和聯系)

1. 使用await,函數必須用async標識
2. await 后面跟的是一個promise實例
    使用了promise,並沒有和promise沖突
    完全是同步的寫法,再也沒有回調函數
    但是:改變不了JS單線程、異步的本質
3. 需要安裝babel-polyfill並,引入
六. 總結當前js異步解決方案
1. jQuery Deferred
2. Promise
3. async/await
4. generator(並不是解決異步的,原理比較復雜,忽略)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM