JavaScript---------异步编程

异步函数为我们提供的能力:

  • 通过调用一个函数来启动一个长期运行的操作
  • 让函数开始操作并立即返回,这样我们的程序就可以保持对其他事件做出反应的能力
  • 当操作最终完成时,通知我们操作的结果

事件处理程序:

事件处理程序实际上就是异步编程的一种形式:你提供的函数(事件处理程序)将在事件发生时被调用(而不是立即被调用)。如果“事件”是“异步操作已经完成”,那么你就可以看到事件如何被用来通知调用者异步函数调用的结果的。

一些早期的异步 API 正是以这种方式来使用事件的。XMLHttpRequest  API 可以让你用 JavaScript 向远程服务器发起 HTTP 请求。由于这样的操作可能需要很长的时间,所以它被设计成异步 API,可以通过给 XMLHttpRequest 对象附加事件监听器来让程序在请求进展和最终完成时获得通知。

例子:

点击“点击发起请求”按钮来发送一个请求。我们将创建一个新的  XMLHttpRequest并监听它的 loadend事件。而我们的事件处理程序则会在控制台中输出一个“完成!”的消息和请求的状态代码,在添加了事件监听器后发送请求。

注意,在这之后,仍然可以在控制台中输出“请求已发起”,也就是说,我们的程序可以在请求进行的同时继续运行,而我们的事件处理程序将在请求完成时被调用。

在HTML文件中:

<button id="xhr">点击发起请求</button>
<button id="reload">重载</button>

<pre readonly class="event-log"></pre>

在JS文件中:

const log = document.querySelector(".event-log");
document.querySelector("#xhr").addEventListener("click", () => {
  log.textContent = "";
  const xhr = new XMLHttpRequest();
  xhr.addEventListener("loadend", () => {
    log.textContent = `${log.textContent}完成!状态码:${xhr.status}`;
  });
  xhr.open(
    "GET",
    "https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json",
  );
  xhr.send();
  log.textContent = `${log.textContent}请求已发起\n`;
});
document.querySelector("#reload").addEventListener("click", () => {
  log.textContent = "";
  document.location.reload();
});

结果展示:

 

这就像模块中的事件处理程序,只是这次的事件不是像点击按钮那样的用户行为,而是某个对象的状态变化。

回调

事件处理程序是一种特殊类型的回调函数。而回调函数则是一个被传递到另一个函数中的会在适当的时候被调用的函数。正如刚刚所看到的:回调函数曾经是 JavaScript 中实现异步函数的主要方式。

然而,当回调函数本身需要调用其他同样接受回调函数的函数时,基于回调的代码会变得难以理解。当你需要执行一些分解成一系列异步函数的操作时,这将变得十分常见。例如下面这种情况:

function doStep1(init) {
  return init + 1;
}
function doStep2(init) {
  return init + 2;
}
function doStep3(init) {
  return init + 3;
}
function doOperation() {
  let result = 0;
  result = doStep1(result);
  result = doStep2(result);
  result = doStep3(result);
  console.log(`结果:${result}`);
}
doOperation();

现在我们有一个被分成三步的操作,每一步都依赖于上一步。在这个例子中,第一步给输入的数据加 1,第二步加 2,第三步加 3。从输入 0 开始,最终结果是 6(0+1+2+3)。

用回调来实现这些步骤:

function doStep1(init, callback) {
  const result = init + 1;
  callback(result);
}
function doStep2(init, callback) {
  const result = init + 2;
  callback(result);
}
function doStep3(init, callback) {
  const result = init + 3;
  callback(result);
}
function doOperation() {
  doStep1(0, (result1) => {
    doStep2(result1, (result2) => {
      doStep3(result2, (result3) => {
        console.log(`结果:${result3}`);
      });
    });
  });
}
doOperation();

因为必须在回调函数中调用回调函数,我们就得到了这个深度嵌套的 doOperation() 函数,这就更难阅读和调试了。

面对这样的嵌套回调,处理错误也会变得非常困难:你必须在每一级处理错误,而不是在最高一级一次完成错误处理。

由于以上这些原因,大多数现代异步 API 都不使用回调,事实上,JavaScript 中异步编程的基础是 Promise。

 

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值