JavaScript的回调函数

简介: 回调函数是一个通过指针调用的函数。如果你把这个指针作为参数传给另一个函数,当这个指针指向的函数被调用的时候,我们就说和这个函数是回调函数。回调函数不是由函数的实现方直接调用的,而是在特定的时间或者条件,由另一方函数调用。


一、撒是回调函数


回调函数是一个通过指针调用的函数。如果你把这个指针作为参数传给另一个函数,当这个指针指向的函数被调用的时候,我们就说和这个函数是回调函数。回调函数不是由函数的实现方直接调用的,而是在特定的时间或者条件,由另一方函数调用。


二、回调函数能干撒


把调用者和被调用者区分开,调用者不关心谁是被调用者,它只需知道存在一个具有特定原型的和限制条件的被调用者函数。简而言之,回调函数允许用户把需要调用的函数作为一个指针传给另一个函数,使程序更加灵活。


三、回调函数的二哈-回调地狱


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等语言中,编写人员期望第一行发生的任何事情都会在第二行代码运行开始之前被完成,依次类推。就会产生上述结果。


回调地狱(二哈拆家)的本质:


  • 嵌套函数存在严重的耦合,牵一发而动全身。
  • 错误处理比较艰难,不能使用try catch 和不能直接return。


四、如何解决二哈拆家


三个原则:

  • 保持代码浅(打二哈)
  • 模块化(打二哈)
  • 处理每一个错误(还是打二哈)


4.1拆解function,将各部拆解为一个一个的function


源代码
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
}


4.2事件发布/监听模式


一方面监听事件发生,如果发生执行相应的回调,另一方面,监听操作的完成,当操作完成时进行相应的回调。


4.3Promise


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);
});


4.4Generator


// 我们的主任务——显示关键字 
// 使用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();


4.5async/await


可以看到,上面的方法虽然都在一定程度上解决了异步编程中回调带来的问题。然而:


  • function拆分的方式其实仅仅只是拆分代码块,时常会不利于后续维护;
  • 事件发布/监听方式模糊了异步方法之间的流程关系;
  • Promise虽然使得多个嵌套的异步调用能够通过链式的API进行操作,但是过多的then也增加了代码的冗余,也对阅读代码中各阶段的异步任务产生了一定干扰;
  • 通过generator虽然能提供较好的语法结构,但是毕竟generator与yield的语境用在这里多少还有些不太贴切。


因此,这里再介绍一个方法,它就是es7中的async/await。

简单介绍一下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');


五、二哈拆家不要怕,防狼喷一喷,轻松解决。


目录
相关文章
|
JavaScript 前端开发 Go
动态加载与异步加载 JavaScript 详解:加载远程js,加载成功后执行回调函数
动态加载与异步加载 JavaScript 详解:加载远程js,加载成功后执行回调函数
2611 2
|
JavaScript 前端开发 UED
在 JavaScript 中,异步编程和回调函数是处理非阻塞操作(如网络请求、文件读写等)的重要工具
【5月更文挑战第10天】JavaScript中的异步编程和回调函数用于处理非阻塞操作,提高应用响应性和吞吐量。异步编程通过回调函数、Promises和async/await等方式实现,避免程序因等待操作完成而阻塞。回调函数是异步操作完成后调用的函数,常用于处理网络请求等。然而,回调函数存在嵌套问题和错误处理困难,因此出现了Promises和async/await等更优解决方案。
153 3
|
JavaScript API
Node.js 回调函数
10月更文挑战第3天
109 0
|
存储 前端开发 JavaScript
回调函数是JavaScript中处理异步编程的常见模式,常用于事件驱动和I/O操作。
【6月更文挑战第27天】回调函数是JavaScript中处理异步编程的常见模式,常用于事件驱动和I/O操作。它作为参数传递给其他函数,在特定条件满足或任务完成后被调用。例如,`asyncOperation`函数接受回调函数`handleResult`,模拟异步操作后,调用`handleResult`传递结果。这样,当异步任务完成时,`handleResult`负责处理结果。
186 1
|
前端开发 JavaScript
JavaScript异步处理避免了单线程阻塞,如回调函数、Promise和async/await。
【6月更文挑战第22天】JavaScript异步处理避免了单线程阻塞,如回调函数、Promise和async/await。回调是基础,用于在操作完成后执行函数;Promise管理异步状态,支持链式调用;async/await提供同步代码外观,简化错误处理。每种技术在处理耗时任务时都起着关键作用。
209 3
|
前端开发 JavaScript 开发者
JavaScript基础-异步编程:回调函数
【6月更文挑战第12天】本文介绍了JavaScript中的异步编程基础,重点讨论回调函数。回调函数是处理延迟操作的关键,常见于事件监听、定时器、Ajax请求和文件操作。然而,它们可能导致回调地狱、错误处理不一致和控制流混乱等问题。为了解决这些问题,文章推荐使用Promise链、async/await来扁平化异步逻辑,并提供了相关代码示例,强调了现代JavaScript特性的优势,以提升代码可读性和可维护性。
328 7
|
JavaScript API
Node.js 回调函数
Node.js 回调函数
98 1
|
前端开发 JavaScript 开发者
JavaScript异步编程艺术:深入浅出回调函数与异步挑战【含代码示例】
本文深入解析JavaScript异步编程,重点探讨回调函数和异步挑战。在单线程的JavaScript中,异步编程至关重要,回调函数是其基础。然而,回调地狱问题催生了Promise和async/await的出现。文章提供代码示例展示Promise和async/await的使用,并分享异步编程最佳实践,包括错误处理、资源管理和性能优化。遇到问题时,建议通过明确异步流程、逐步调试和异常捕获来解决。最后,文章强调异步编程的未来发展,鼓励开发者掌握最新工具并探讨更高效的异步解决方案。
154 2
|
JavaScript 前端开发 API
Node中的AsyncLocalStorage 使用问题之Node.js将 JavaScript 层的 nativeHooks 注册到 C++ 层的问题如何解决
Node中的AsyncLocalStorage 使用问题之Node.js将 JavaScript 层的 nativeHooks 注册到 C++ 层的问题如何解决
144 0