上篇文章《JavaScript基礎——你真的瞭解JavaScript嗎?》,咱們明白了JavaScript是一個單線程、非阻塞、異步、解釋性語言,清楚了什麼是單線程、進程、阻塞、調用堆棧、異步回調、任務循環等感念,沒看的或者不清楚的建議點擊《JavaScript基礎——你真的瞭解JavaScript嗎?》再看一遍,只有理解了,才能輕鬆閱讀理解本篇文章內容。前端
JavaScript 是單線程工做,這意味着兩段腳本不能同時運行,而是必須一個接一個地運行。咱們人類是多線程工做。您可使用多個手指打字,能夠一邊開車一邊與人交談。惟一一個會妨礙咱們的是打噴嚏,由於當咱們打噴嚏的時候,全部當前進行的活動都必須暫停。這真是很是討厭,尤爲是當您在開車並想與人交談時。您可不想編寫像打噴嚏似的代碼。JavaScript因爲單線程限制,防止阻塞,只能經過異步函數的調用方式,把須要延遲處理的事件放入事件循環隊列。到目前爲止,回調是編寫和處理JavaScript程序異步邏輯的最經常使用方式。說了這麼多,既然回調這麼重要,到底什麼是回調(callback)呢?數據庫
function first(){
console.log(1);
}
function second(){
console.log(2);
}
first();
second();複製代碼
1
2複製代碼
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();複製代碼
2
1複製代碼
function doHomework(subject) {
alert(`Starting my ${subject} homework.`);
}複製代碼
doHomework('math');
// Alerts: Starting my math homework.複製代碼
function doHomework(subject, callback) {
alert(`Starting my ${subject} homework.`);
callback();
}
doHomework('math', function() {
alert('Finished my homework');
});
複製代碼
正如你但願的,咱們在控制檯裏運行上述代碼,將會受到兩個連續的alert,Starting my math homework,而後彈出 Finished my homework。編程
可是回調函數並非非得在調用函數中定義,咱們能夠單獨定義,修改後的代碼以下:json
function doHomework(subject, callback) {
alert(`Starting my ${subject} homework.`);
callback();
}
function alertFinished(){
alert('Finished my homework');
}
doHomework('math', alertFinished);
複製代碼
此示例的輸出結果和上段代碼的結果一致,咱們實現了在doHomework函數中調用alertFinished,實現了函數做爲參數進行傳遞,實現了回調函數的建立。
bash
例如咱們有一個需求,用NodeJs實現從論壇帖子列表中顯示其中的一個帖子的信息及留言列表信息,代碼以下:微信
[
{
"id": "001",
"title": "Greeting",
"text": "Hello World",
"author": "Jane Doe"
},
{
"id": "002",
"title": "JavaScript 101",
"text": "The fundamentals of programming.",
"author": "Alberta Williams"
},
{
"id": "003",
"title": "Async Programming",
"text": "Callbacks, Promises and Async/Await.",
"author": "Alberta Williams"
}
]複製代碼
[
{
"id": "phx732",
"postId": "003",
"text": "I don't get this callback stuff."
},
{
"id": "avj9438",
"postId": "003",
"text": "This is really useful info."
},
{
"id": "gnk368",
"postId": "001",
"text": "This is a test comment."
}
]複製代碼
const fs = require('fs');
const path = require('path');
const postsUrl = path.join(__dirname, 'db/posts.json');
const commentsUrl = path.join(__dirname, 'db/comments.json');
//return the data from our file
function loadCollection(url, callback) {
fs.readFile(url, 'utf8', function(error, data) {
if (error) {
console.log(error);
} else {
return callback(JSON.parse(data));
}
});
}
//return an object by id
function getRecord(collection, id, callback) {
var collectobj=collection.find(function(element){
return element.id == id;
});
callback(collectobj);
return collectobj;
}
//return an array of comments for a post
function getCommentsByPost(comments, postId) {
return comments.filter(function(comment){
return comment.postId == postId;
});
}
loadCollection(postsUrl, function(posts){
loadCollection(commentsUrl, function(comments){
getRecord(posts, "001", function(post){
const postComments = getCommentsByPost(comments, post.id);
console.log(post);
console.log(postComments);
});
});
});
複製代碼
你們請注意,咱們在loadCollection函數中咱們沒有使用try/catch,使用的是if/else,由於catch沒法從readFile方法中獲取錯誤。上述代碼還須要完善,我沒有包含任何錯誤處理。若是在任何步驟中發生錯誤,程序將沒法繼續。
多線程
錯誤處理是很重要的事情,咱們寫代碼時要認證對待,要嚴格對待,好比咱們要編寫一個用戶登陸的功能。涉及從網頁表單裏獲取用戶名和密碼,查詢咱們的數據庫,確認用戶信息是否正確,驗證經過後,將用戶引導到用戶中心頁面。若是用戶名密碼格式不正確,用戶名密碼不正確,咱們應該將錯誤信息返回給用戶,並引導用戶從新登陸。異步
很好!咱們一塊兒把回調的內容學完了,理解了什麼是回調,異步編程是咱們的代碼中使用的一種方法,用於推遲事件以便之後執行。當您處理異步任務時,回調是一種解決方案,以便它們按順序執行。編輯器
若是咱們有多個任務依賴於前幾個任務的結果,那咱們就要使用多個嵌套回調,可是就會引起「回調地域」(過多的回調嵌套會使得代碼變得難以理解與維護),還好Promise解決了「回調地獄」的問題,讓咱們以同步的方式編寫代碼,小編將會再下篇文章裏進行詳細介紹,敬請期待!異步編程
更多精彩內容,請微信關注」前端達人」公衆號!