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)
})
問題解答:
- new promise實例,而且要傳入return
- new promise時要傳入函數,函數有resolve reject函數
- 成功時執行resolve()失敗時執行reject()
- .then監聽結果
ES6常用功能
- let 定義變量,可以重新賦值
- const 定義常量,不可以重新賦值
- 多行字符串/模板變量
- 解構賦值(詳情見es6)
- 塊級作用域(很大的改動)
- 函數默認參數
- 箭頭函數
塊級作用域
<!-- 在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是原型方法
原型如何體現他的擴展性
異步
問題:
一. 什么是單線程,和異步有什么關系
- 單線程只有一個線程,同一時間只能做一件事情
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);
用單線程的原因-避免DOM渲染的沖突
瀏覽器需要渲染DOM
js可以修改DOM結構
JS執行的時候,瀏覽器DOM渲染會暫停
兩段JS也不能同時執行(都修改DOM就沖突了)
webworder支持多線程,但是不能訪問DOM
單線程的解決單線程方案-異步
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 異步的解決方案。
- 事件輪詢,js實現異步的具體解決方案
- 同步代碼,直接執行
- 異步函數先放在異步隊列中;有setTimeout等待時間過后,才放入異步隊列中。ajax執行完畢過后放入異步隊列
- 待同步函數執行完畢,輪詢執行異步隊列的函數
回答點:
- 什么是異步隊列,何時被放入異步隊列
- 輪詢的過程。
三. 是否用過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之后 這樣寫的好處:
- 這樣對修改封閉,對擴展開放,
- 增加一個函數,不用再修改原來的函數
- 多人開發,一人維護一個函數。
- 測試也只測試新的函數。
- 對代碼管理和維護有好處的
// 每一個方法都會執行
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');
})
- 無法改變js異步和單線程的本質
- 只能從寫法上杜絕callback這種形式
- 它是一種語法糖形式,但是解耦了代碼
- 很好的體現:開放封閉原則
- 減少了回歸測試的成本。多人開發方便。
使用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(並不是解決異步的,原理比較復雜,忽略)