Javascript高级-回调与异步

✊不积跬步,无以至千里;不积小流,无以成江海。

同步地摇色子、异步地摇色子

同步的摇骰子

在 JavaScript 中模拟同步地摇色子,可以使用 setTimeout 函数来模拟掷色子的延迟效果。以下是一个简单的示例代码,展示如何同步地摇色子并输出结果:

javascript 复制代码
function rollDice() {
  return Math.floor(Math.random() * 6) + 1;
}

function shakeDice() {
  // 模拟掷色子的延迟效果
  function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async function shake() {
    console.log('Shaking dice...');
    await delay(1000); // 延迟1秒

    const dice1 = rollDice();
    const dice2 = rollDice();

    console.log('Dice 1:', dice1);
    console.log('Dice 2:', dice2);
  }

  shake();
}

shakeDice();

在上述代码中,我们定义了 rollDice 函数来模拟摇色子并返回一个随机的骰子点数。

然后,我们定义了 shakeDice 函数来模拟同步地摇色子。在 shakeDice 函数内部,我们使用了 setTimeout 和 Promise 的结合来模拟摇色子的延迟效果。

我们定义了 delay 函数,它返回一个 Promise,并使用 setTimeout 在指定的毫秒数后解析该 Promise。这样,我们可以通过 await delay(1000) 来实现延迟1秒的效果。

接下来,我们使用 asyncawait 关键字定义了内部的 shake 异步函数。在 shake 函数中,我们首先打印出 "Shaking dice...",然后通过 await delay(1000) 延迟1秒。

随后,我们调用 rollDice 函数两次来模拟掷两个骰子,并将结果保存在 dice1dice2 变量中。

最后,我们打印出骰子的结果。

通过调用 shakeDice 函数,我们可以执行同步地摇色子的操作。当调用 shakeDice 函数时,它会按顺序执行内部的异步函数,并模拟出摇色子的延迟效果。最终,我们可以在控制台上看到摇色子的结果。

请注意,由于使用了 asyncawait,这段代码需要在支持 ES6 或更高版本的 JavaScript 环境中运行。

new Promise(resolve => setTimeout(resolve, ms))

这句代码是创建一个 Promise 对象,并使用 setTimeout 函数来延迟 Promise 的解析。

逐步解释这句代码的含义:

  1. new Promise() 创建一个新的 Promise 对象。Promise 是 JavaScript 中处理异步操作的一种机制,它表示一个可能会在未来完成失败的操作。
  2. resolve 是一个函数,它是 Promise 构造函数的参数。当 Promise 成功解析时,我们可以调用 resolve 函数来触发 Promise 的成功状态。
  3. setTimeout() 是一个 JavaScript 函数,它用于在指定的延迟时间后执行一个函数或表达式。
  4. setTimeout(resolve, ms)resolve 函数作为参数传递给 setTimeout 函数。这意味着在经过指定的延迟时间(ms 毫秒)后,resolve 函数将被调用。

因此,整个表达式 new Promise(resolve => setTimeout(resolve, ms)) 的作用是创建一个 Promise 对象,并在经过指定的延迟时间后解析(resolve)该 Promise。这样,我们可以使用 await 关键字来等待这个 Promise 的解析,从而实现延迟的效果。

例如,如果我们使用 await delay(1000),它将等待 1000 毫秒(即 1 秒),然后继续执行后续的代码。这样就可以模拟出延迟的效果,让后续的操作在一定的时间间隔后执行。

async 和 await 语法

asyncasync 关键字用于声明一个函数是异步函数(async function)。异步函数内部可以包含 await 关键字。

语法:

csharp 复制代码
async function functionName() {
  // 异步操作
}

异步函数在执行时,会返回一个 Promise 对象。这个 Promise 对象将在异步操作完成后进行解析(resolve),并且可以使用 await 关键字来等待 Promise 的解析结果。

awaitawait 关键字只能在异步函数内部使用,用于等待一个 Promise 对象的解析结果。await 关键字会暂停异步函数的执行,直到等待的 Promise 对象解析完成,并返回解析结果。

语法:

ini 复制代码
const result = await promise;

await 关键字后面跟着一个 Promise 对象,它可以是任何返回 Promise 的异步操作,例如异步函数调用、fetch 请求、定时器等。当 await 关键字执行时,它会等待 Promise 对象的解析结果,并将解析结果赋值给 result 变量。

在使用 await 关键字时,需要将其放置在 async 函数内部,并且 async 函数本身需要被调用或使用其他方式触发执行。

异步的摇骰子

在 JavaScript 中异步地摇色子,可以使用 PromisesetTimeout 来模拟异步操作的延迟效果。以下是一个可运行的代码示例:

javascript 复制代码
function rollDice() {
  return new Promise(resolve => {
    setTimeout(() => {
      const dice = Math.floor(Math.random() * 6) + 1;
      resolve(dice);
    }, 1000); // 延迟1秒模拟摇色子的过程
  });
}

async function shakeDice() {
  console.log('Shaking dice...');

  const dice1Promise = rollDice();
  const dice2Promise = rollDice();

  const [dice1, dice2] = await Promise.all([dice1Promise, dice2Promise]);

  console.log('Dice 1:', dice1);
  console.log('Dice 2:', dice2);
}

shakeDice();

在上述代码中,我们定义了 rollDice 函数,它返回一个 Promise 对象。在 Promise 的回调函数中,我们使用 setTimeout 来模拟延迟1秒的摇骰子过程,并将骰子的点数作为解析结果传递给 resolve 函数。

然后,我们定义了一个 async 函数 shakeDice,用于异步地摇色子。在 shakeDice 函数中,我们首先打印出 "Shaking dice..."。

接下来,我们调用 rollDice 函数两次,分别返回两个 Promise 对象 dice1Promisedice2Promise,代表两个骰子的摇色子操作。

使用 await Promise.all([dice1Promise, dice2Promise]),我们等待两个 Promise 对象同时解析,并将解析结果存储在 dice1dice2 变量中。这里使用 Promise.all 方法可以并行地等待多个 Promise 对象的解析结果。

最后,我们打印出两个骰子的结果。

通过调用 shakeDice 函数,我们可以执行异步地摇色子的操作。在摇色子过程中,我们使用了异步操作的延迟效果,并通过 await 关键字等待两个骰子的解析结果。最终,我们可以在控制台上看到异步摇色子的结果。

请注意,由于使用了 asyncawait,这段代码需要在支持 ES6 或更高版本的 JavaScript 环境中运行。

setTimeout 的回调函数

javascript 复制代码
setTimeout(() => {  
const dice = Math.floor(Math.random() * 6) + 1;  
resolve(dice);

这段代码是在 setTimeout 的回调函数中执行的操作。

逐步解释这段代码的含义:

  1. setTimeout() 是一个 JavaScript 函数,它用于在指定的延迟时间后执行一个函数或表达式。
  2. setTimeout(() => { ... }, delay) 接受两个参数:第一个参数是一个函数或表达式,表示要执行的操作;第二个参数是延迟的时间(以毫秒为单位)。
  3. () => { ... } 是一个箭头函数 (也称为匿名函数 ),它是作为 setTimeout 的第一个参数传递的回调函数。箭头函数的作用是定义一个函数体,以便在延迟时间结束后执行。
  4. 在箭头函数的函数体中,我们生成一个随机数来模拟骰子的点数。Math.random() 用于生成一个介于 0 到 1 之间的随机数,然后通过乘以 6 和加 1 的操作,将其转换为一个介于 1 到 6 之间的随机整数(骰子的点数)。
  5. resolve(dice) 是调用 Promise 的 resolve 方法,并将生成的随机数(骰子的点数)作为参数传递给它。这样,Promise 的状态将被设置为已解析,并将生成的随机数作为解析结果。

因此,这段代码的作用是在延迟时间结束后,生成一个随机数(骰子的点数),并通过 resolve 方法将该随机数作为 Promise 的解析结果。这样,在调用 rollDice 函数并等待它的解析结果时,我们将得到一个模拟骰子点数的异步操作。

const [dice1, dice2] = await Promise.all([dice1Promise, dice2Promise]);

这段代码使用了 await 关键字和 Promise.all 方法来等待多个 Promise 对象同时解析,并将它们的解析结果分配给相应的变量。

逐步解释这段代码的含义:

  1. Promise.all([dice1Promise, dice2Promise]) 是一个将多个 Promise 对象作为参数的方法。它返回一个新的 Promise 对象,该 Promise 对象将在传入的所有 Promise 对象都解析完成后进行解析。
  2. await 关键字用于等待一个 Promise 对象的解析结果。在这段代码中,我们使用 await 等待 Promise.all([dice1Promise, dice2Promise]) 的解析结果。
  3. const [dice1, dice2] 是一种解构赋值语法,用于从一个数组中提取元素并分配给相应的变量。在这段代码中,我们将 Promise.all 返回的解析结果数组的第一个元素赋值给 dice1 变量,将第二个元素赋值给 dice2 变量。

因此,这段代码的作用是等待 dice1Promisedice2Promise 两个 Promise 对象同时解析,并将它们的解析结果分配给 dice1dice2 变量。通过这种方式,我们可以同时获取两个骰子的点数,并在后续的代码中使用这些值进行处理。

同步和异步的区别

使用同步和异步方法摇骰子有以下区别:

  1. 执行顺序 :同步方法是按照代码的顺序依次 执行,代码会一直等待当前操作完成后 执行下一个操作。异步方法则是不会阻塞 代码的执行,它会在进行耗时的操作时,继续 执行后续的代码,待操作完成后再执行相应的回调函数或者通过 await 等待结果。
  2. 阻塞:同步方法会阻塞代码的执行,即代码会一直等待当前操作完成后才能继续执行后续代码。异步方法则不会阻塞代码的执行,它会在进行异步操作时,立即返回并允许后续代码继续执行。
  3. 响应性:异步方法能够提升应用的响应性能,因为它不会阻塞主线程,允许同时处理其他任务或事件。这在处理大量或耗时的操作时特别有用,可以避免应用程序的冻结或卡顿。
  4. 代码结构:异步方法通常使用回调函数、Promise 或 async/await 来处理异步操作,这使得代码更具可读性和可维护性。相比之下,同步方法可能需要使用回调地狱(callback hell)或者复杂的控制流程来处理异步操作,使代码变得难以理解和维护。

总的来说,异步方法允许在进行耗时的操作时,不阻塞代码的执行,提高了应用的响应性能,并通过更简洁的代码结构提供了更好的可读性和可维护性。而同步方法则会阻塞代码的执行,可能导致应用程序的冻结或卡顿,以及复杂的代码结构。

什么是异步、轮询与回调

异步、轮询和回调是与处理异步操作相关的概念。

  1. 异步(Asynchronous):异步是指在进行某个操作时,不会阻塞程序的执行,而是允许程序继续执行其他任务。异步操作通常是耗时的操作,比如网络请求、文件读写等,为了避免阻塞主线程,将这些操作放在后台执行,并在操作完成后通知程序。
  2. 轮询(Polling):轮询是一种常见的处理异步操作的方式。它通过定期(或间隔性)地查询某个资源的状态或结果,来判断操作是否完成。在轮询中,程序会重复地发起查询请求,直到获取到所需的结果或达到指定的条件。
  3. 回调(Callback) :回调是一种处理异步操作的模式。在回调模式中,我们将一个函数 (回调函数)作为参数 传递给另一个函数,当异步操作完成时,调用该回调函数来处理结果。回调函数可以用于处理异步操作的结果、错误处理或执行其他逻辑。

例如,当进行网络请求时,可以使用异步操作来避免阻塞主线程。轮询可以用于定期查询请求的状态,直到请求完成或达到超时条件。回调函数则可以用于在请求完成后处理返回的数据或处理错误。

什么是回调地狱

回调地狱(Callback Hell)是指在回调函数嵌套过多、代码结构复杂的情况下,代码变得难以理解和维护的现象。

在使用回调函数处理异步操作时,如果多个异步操作之间存在依赖关系,通常需要在一个回调函数中嵌套另一个回调函数。当异步操作嵌套层级过多时,代码会出现多层嵌套的回调函数,导致代码结构复杂,可读性变差,称为回调地狱。

回调地狱的问题包括:

  1. 可读性差:多层嵌套的回调函数使得代码难以阅读和理解,增加了代码的复杂性。
  2. 可维护性差:由于嵌套的回调函数,修改和调试代码变得困难,容易出错,增加了代码的维护成本。
  3. 错误处理困难:对于多个异步操作的错误处理,需要在每个回调函数中进行处理,导致错误处理代码分散且容易遗漏。
  4. 可扩展性差:在回调地狱中添加新的异步操作变得复杂,需要进一步嵌套回调函数,使代码变得混乱。

为了解决回调地狱问题,出现了 Promise、Async/Await 等新的异步编程模型。这些模型提供了更优雅、可读性更好的方式处理异步操作,避免了多层嵌套的回调函数,使代码更加清晰、简洁和易于维护。

Node风格的回调

Node.js 风格的回调是一种在 Node.js 中广泛采用的异步编程模式,它基于回调函数来处理异步操作的结果或错误。

Node.js 风格的回调通常具有以下特征:

  1. 回调函数作为最后一个参数:异步函数通常将回调函数作为其参数列表中的最后一个参数。回调函数用于处理异步操作的结果或错误信息。
  2. 错误优先的回调函数:回调函数的第一个参数通常是错误对象(通常命名为 errerror),用于传递异步操作可能发生的错误。如果没有错误发生,则该参数为 nullundefined
  3. 回调函数的其他参数:在错误参数之后,回调函数可能会包含其他参数,用于传递异步操作的结果或其他相关信息。

下面是一个使用 Node.js 风格的回调的示例:

javascript 复制代码
function fetchData(callback) {
  // 模拟异步操作
  setTimeout(() => {
    const data = 'Hello, World!';
    const error = null;

    // 调用回调函数,传递错误和数据
    callback(error, data);
  }, 2000);
}

// 调用异步函数并处理回调结果
fetchData((err, result) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('Data:', result);
  }
});

在上述示例中,fetchData 函数是一个模拟的异步操作,通过回调函数将结果返回。在回调函数中,根据是否有错误,进行相应的处理。

Node.js 风格的回调模式在 Node.js 生态系统中被广泛采用,但它也容易导致回调地狱(callback hell)的问题。为了解决这个问题,可以使用 Promise、Async/Await 等更现代的异步编程模型来提高代码的可读性和可维护性。

相关推荐
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic2 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
清灵xmf4 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据4 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
334554324 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test4 小时前
js下载excel示例demo
前端·javascript·excel
PleaSure乐事5 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶5 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json