上篇文章《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解决了“回调地狱”的问题,让咱们以同步的方式编写代码,小编将会再下篇文章里进行详细介绍,敬请期待!异步编程
更多精彩内容,请微信关注”前端达人”公众号!