何為回調函數
1 setTimeout(function () { 2 console.log('callback...'); 3 }, 1000);
此延時定時器中的function就是我們常說的回調函數,回調函數常常滿足三個特征
- 我們自己定義的
- 我們自己沒去執行
- 最終被其它人(瀏覽器的ajax模塊,定時器模塊...)執行了
何為回調地獄
1 setTimeout(function (name) { 2 var catList = name + ','; 3 4 setTimeout(function (name) { 5 catList += name + ','; 6 7 setTimeout(function (name) { 8 catList += name + ','; 9 10 setTimeout(function (name) { 11 catList += name + ','; 12 13 setTimeout(function (name) { 14 catList += name; 15 16 console.log(catList); 17 18 }, 1, 'Lion'); 19 20 }, 1, 'Snow Leopard'); 21 22 }, 1, 'Lynx'); 23 24 }, 1, 'Jaguar');}, 1, 'Panther');
由於回調函數是異步的,在上面的代碼中每一層的回調函數都需要依賴上一層的回調執行完,所以形成了層層嵌套的關系最終形成類似上面的回調地獄,但代碼以此種形式展現時無疑是不利於我們閱讀與維護的,此時就要想辦法改進這種代碼形式。
初次改進
var catList = ''; setTimeout(getPanther, 1, 'Panther'); function getPanther(name) { catList += name + ','; setTimeout(getJanguar, 1, 'Janguar'); } function getJanguar(name) { catList += name + ','; setTimeout(getLynx, 1, 'Lynx'); } function getLynx(name) { catList += name + ','; setTimeout(getSnowLeopard, 1, 'Snow Leopard'); } function getSnowLeopard(name) { catList += name + ','; setTimeout(getLion, 1, 'Lion'); } function getLion(name) { catList += name; setTimeout(print, 1); } function print() { console.log(catList); }
將匿名函數命名
雖然匿名函數使用方便,但是不利於我們閱讀與書寫,所以我們選擇將回調函數單獨的拿出來並命名,寫成如上形式,這樣看上去就要比第一次的代碼優雅清晰很多。需要注意的是上面的代碼相比之前有了幾點改變。
1. catList變成了全局變量
2. 函數的作用域發生了變化,從局部作用域變成了全局作用域,所以才需要將catList變成全局變量以保證每個函數都可以訪問的到
通常情況下我們不希望有全局變量污染環境,並且上面的代碼還有一些可以復用的空間,可以看到我們在每個函數中都重復的調用定時器,所以我們可以再來改進一下上面的代碼。
再次改進
1 function buildCatList(list, returnVal, fn) { 2 setTimeout(function (name) { 3 var catList = list === '' ? name : list + ',' + name; 4 fn(catList); 5 }, 1, returnVal); 6 } 7 8 9 buildCatList('', 'Panther', getJanguar); 10 11 function getJanguar(list) { 12 buildCatList(list, 'Janguar', getLynx); 13 } 14 15 function getLynx(list) { 16 buildCatList(list, 'Lynx', getSnowLeopard); 17 } 18 19 function getSnowLeopard(list) { 20 buildCatList(list, 'Snow Leopard', getLion); 21 } 22 23 function getLion(list) { 24 buildCatList(list, 'Lion',print); 25 } 26 27 function print(list) { 28 console.log(list); 29 }
定時器中的回調函數處在外層函數中的作用域內,並通過參數傳入,沒有產生全局變量,沒有重復代碼。
