回調函數是一個經過指針調用的函數。若是你把這個指針做爲參數傳給另外一個函數,當這個指針指向的函數被調用的時候,咱們就說和這個函數是回調函數。回調函數不是由函數的實現方直接調用的,而是在特定的時間或者條件,由另外一方函數調用。java
把調用者和被調用者區分開,調用者不關心誰是被調用者,它只需知道存在一個具備特定原型的和限制條件的被調用者函數。簡而言之,回調函數容許用戶把須要調用的函數做爲一個指針傳給另外一個函數,使程序更加靈活。編程
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
複製代碼
回調地獄的緣由是當編寫人員以重上往下視覺方式編寫JavaScript。不少人都會犯這個錯誤!在C,java,Ruby,Python等語言中,編寫人員指望第一行發生的任何事情都會在第二行代碼運行開始以前被完成,依次類推。就會產生上述結果。promise
三個原則:bash
源代碼
var form = document.querySelector('form')
form.onsubmit = function (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
複製代碼
代碼分解
document.querySelector('form').onsubmit = formSubmit
function formSubmit (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
複製代碼
一方面監聽事件發生,若是發生執行相應的回調,另外一方面,監聽操做的完成,當操做完成時進行相應的回調。異步
readFile('./sample.txt').then(content => {
let keyword = content.substring(0, 5);
return queryDB(keyword);
}).then(res => {
return getData(res.length);
}).then(data => {
console.log(data);
}).catch(err => {
console.warn(err);
});
複製代碼
// 咱們的主任務——顯示關鍵字
// 使用yield暫時中斷下方代碼執行
// yield後面爲promise對象
const showKeyword = function* (filepath) {
console.log('開始讀取');
let keyword1 = yield readFile(filepath);
let keyword2 = yield readFile(filepath);
}
// generator的流程控制
let gen = showKeyword();
let res = gen.next();
let res1 = gen.next();
複製代碼
能夠看到,上面的方法雖然都在必定程度上解決了異步編程中回調帶來的問題。然而:async
所以,這裏再介紹一個方法,它就是es7中的async/await。ide
簡單介紹一下async/await。基本上,任何一個函數均可以成爲async函數,如下都是合法的書寫形式:模塊化
const printData = async function (filepath) {
let keyword = await readFile(filepath);
let count = await queryDB(keyword);
let data = await getData(res.length);
console.log(data);
});
printData('./sample.txt');
複製代碼