JavaScript异步编程:(回调函数、Promise、async/await、Generator)

news2024/12/30 0:58:14

文章目录

  • 前言
  • 1. 回调函数
    • 1.1. 回调函数的基本概念和使用方法
    • 1.2. 回调函数的优缺点和注意事项
    • 1.3. 回调地狱和如何避免
  • 2. Promise
    • 2.1. Promise 的基本概念和使用方法
    • 2.2. Promise 的状态和状态转换
    • 2.3. Promise 的链式调用和错误处理
    • 2.4. Promise.all 和 Promise.race 的使用方法
  • 3. async/await
    • 3.1. async/await 的基本概念和使用方法
    • 3.2. async/await 和 Promise 的关系
    • 3.3. async/await 的错误处理方法
  • 4. Generator
    • 4.1. Generator 的基本概念和使用方法
    • 4.2. Generator 和异步编程的结合
    • 4.3. Generator 的错误处理方法
  • 5. 其他异步编程技术
    • 5.1. 事件监听器
    • 5.2. setInterval 和 setTimeout
  • 6. 异步编程的最佳实践
    • 6.1. 如何优化异步编程性能

前言

JavaScript 中异步编程的目的是允许代码执行非阻塞操作。这很重要,因为 JavaScript 是一种单线程语言,意味着一次只能执行一个任务。异步编程允许同时执行多个任务,提高性能和响应能力。

JavaScript 中有几种异步编程技术,包括回调函数Promiseasync/await生成器

以下是 JavaScript 异步编程的简单概述:

1. 回调函数

1.1. 回调函数的基本概念和使用方法

JavaScript 中回调函数是指将一个函数作为参数传递给另一个函数,并在另一个函数执行完后调用该函数。回调函数通常用于处理异步操作,比如向服务器发送请求并在请求返回后执行某些操作。

以下是回调函数的基本使用方法:

// 1. 创建一个需要执行的函数。
function doSomething(callback) {
  console.log("doSomething");
  callback();
}

// 2. 创建一个回调函数。
function callback() {
  console.log("callback");
}

// 3. 调用需要执行的函数,并将回调函数作为参数传递进去。
doSomething(callback);

以上代码将依次输出 doSomethingcallback

1.2. 回调函数的优缺点和注意事项

回调函数的优点包括:

  • 可以处理异步操作,允许代码执行非阻塞操作,提高性能和响应能力。
  • 可以实现代码的模块化和可重用性。

回调函数的缺点和注意事项包括:

  • 错误处理:如果回调函数中出现错误,需要对错误进行处理,否则可能会导致程序崩溃。
  • 可能会产生竞态条件(race condition):如果多个回调函数同时修改同一个变量,可能会出现竞态条件,导致程序出现不可预料的结果。
  • 可能会产生回调地狱(callback hell):如果回调函数嵌套过多,代码可读性会变差,难以维护。

例子:模拟一个回调地狱

function step1(callback) {
  setTimeout(function() {
    console.log('Step 1 done');
    callback();
  }, 1000);
}

function step2(callback) {
  setTimeout(function() {
    console.log('Step 2 done');
    callback();
  }, 1000);
}

function step3(callback) {
  setTimeout(function() {
    console.log('Step 3 done');
    callback();
  }, 1000);
}

step1(function() {
  step2(function() {
    step3(function() {
      console.log('All steps done');
    });
  });
});

如果有一百个回调函数,请问阁下如何应对?

1.3. 回调地狱和如何避免

为了避免回调地狱,建议使用 Promiseasync/awaitPromises 允许链接异步操作,而 async/await 则使编写异步代码更容易以同步方式进行。此外,将复杂的回调拆分为较小的函数也可以帮助提高可读性和可维护性。

2. Promise

2.1. Promise 的基本概念和使用方法

PromiseJavaScript 中一种用于处理异步操作的对象。Promise 对象表示一个可能还没有完成的异步操作,并且可以指定在异步操作完成时如何处理结果

以下是 Promise 的基本使用方法:

const promise = new Promise(function(resolve, reject) {
  // 异步操作
  if (/* 异步操作成功 */) {
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // 异步操作成功时的处理
}, function(error) {
  // 异步操作失败时的处理
});

在这个例子中,promise 对象表示一个异步操作。new Promise 构造函数接受一个函数作为参数,这个函数又接受两个函数作为参数:resolvereject。当异步操作成功时,调用 resolve 函数并传递一个值;当异步操作失败时,调用 reject 函数并传递一个错误对象。

promise.then 方法用于指定在异步操作完成时如何处理结果。then 方法接受两个函数作为参数:一个用于处理异步操作成功时的结果,另一个用于处理异步操作失败时的结果。

2.2. Promise 的状态和状态转换

Promise 对象有三种状态:pending(等待中)、fulfilled(已成功)和rejected(已失败)。

Promise 对象被创建时,它的状态是 pending。当异步操作成功时,可以调用 resolve 函数并将结果传递给它,这样 Promise 对象的状态就会从 pending 转变为 fulfilled。当异步操作失败时,可以调用 reject 函数并将错误传递给它,这样 Promise 对象的状态就会从 pending 转变为 rejected

const promise = new Promise(function(resolve, reject) {
  // 异步操作
  if (/* 异步操作成功 */) {
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // 异步操作成功时的处理
}, function(error) {
  // 异步操作失败时的处理
});

2.3. Promise 的链式调用和错误处理

以下是 Promise 的链式调用:

const promise = new Promise(function(resolve, reject) {
  // 异步操作
});

promise.then(function(result1) {
  // 处理结果1
  return result1;
}).then(function(result2) {
  // 处理结果2
  return result2;
}).then(function(result3) {
  // 处理结果3
  return result3;
}).catch(function(error) {
  // 处理错误
  console.log(error);
});

在这个例子中,在 promise 对象上调用 then 方法可以指定在异步操作完成时如何处理结果。如果在 then 方法中返回一个值,该值也可以被下一个 then 方法中的函数使用。如果在 then 方法中抛出一个错误,或者在前面的异步操作中出现了错误,那么错误会被传递到 catch 方法中处理。

Promise 为什么可以链式调用?

  1. 如果then的回调函数返回一个Promise实例对象,那么下一个then会得到它的异步结果
  2. 如果then的回调函数没有任何返回值,那么会默认返回一个Promise实例对象
  3. 如果then的回调函数中返回一个具体的数据(如字符串数字等),那么下一个then可以直接获取该数据(会自动包装成Promise对象)
let p1 = new Promise((resolve, reject) => {
  resolve("hello p1");
});

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("hello p2");
  }, 3000);
});

p1.then((ret) => {
  // 获取异步的正常结果
  console.log(ret); // hello p1
  // 此处的返回值是什么?Promise实例对象
  // 如果这里返回Promise实例对象,那么下一个then会得到该异步任务的结果
  return p2;
})
  .then((ret) => {
    console.log(ret); // hello p2
    // 如果这里返回的是普通数据,那么下一个then会得到该数据
    return "hello 普通数据";
  })
  .then((ret) => {
    console.log(ret); // hello 普通数据
    // 如果这里没有任何返回值,那么会默认返回一个Promise实例对象
  })
  .then((ret) => {
    console.log(ret); // undefined
  })
  .catch((err) => {
    // 获取错误的提示信息
    console.log(err);
  });

上面的例子依次打印出:hello p1hello p2hello 普通数据undefined

在这里插入图片描述

2.4. Promise.all 和 Promise.race 的使用方法

Promise.all 方法用于并行执行多个异步操作,并在所有异步操作都完成时返回结果;
以下是使用 Promise.all 的示例:

const promises = [
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
];

Promise.all(promises)
  .then(values => console.log(values))
  .catch(error => console.error(error));

在此示例中,我们创建了一个 promise 数组并将其传递给 Promise.all。当所有输入的 promises 都被 resolved 时,结果 promise 的 then 方法将被调用,并带有一个解决值的数组。如果任何一个输入的 promise 被 rejected,结果 promise 的 catch 方法将被调用,并带有错误信息。

在这里插入图片描述

模拟实际项目中 Promise.all() 方法的使用

import { getList, getDetail, getInfo } from "@/api/list.js";

const p1 = new Promise((resolve, reject) => {
  getList({ pageSize: 10, pageNum: 1 })
    .then((res) => {
      resolve(res.data);
    })
    .catch((err) => {
      reject(err);
    });
});
const p2 = new Promise((resolve, reject) => {
  getDetail({ id: 1 })
    .then((res) => {
      resolve(res.data);
    })
    .catch((err) => {
      reject(err);
    });
});
const p3 = new Promise((resolve, reject) => {
  getInfo()
    .then((res) => {
      resolve(res.data);
    })
    .catch((err) => {
      reject(err);
    });
});

Promise.all([p1, p2, p3])
  .then((res) => {
    // 此处的res就是p1, p2, p3传递过来的数组,是一个数组
    console.log(res);
  })
  .catch((err) => {
    console.log(err);
  });

Promise.race 方法用于并行执行多个异步操作,接受一个 promise 数组并返回一个新的 promise,并在其中任何一个异步操作完成时返回结果。
以下是使用 Promise.race 的示例:

const promises = [
  new Promise(resolve => setTimeout(resolve, 1000, 'one')),
  new Promise(resolve => setTimeout(resolve, 2000, 'two')),
  new Promise(resolve => setTimeout(resolve, 3000, 'three'))
];

Promise.race(promises)
  .then(value => console.log(value))
  .catch(error => console.error(error));

在此示例中,我们创建了一个 resolve 速度不同的 promise 数组。当任何一个输入的 promise 被 resolved 时,结果 promise 的 then 方法将被调用,并带有第一个被 resolved 的 promise 的值。如果任何一个输入的 promise 被 rejected,结果 promise 的 catch 方法将被调用,并带有错误信息。

在这里插入图片描述

3. async/await

3.1. async/await 的基本概念和使用方法

async/await 是JavaScript处理异步操作的较新语法。它允许您编写异步代码,看起来和行为类似于同步代码,使其更易于阅读和维护。

以下是使用async/await的示例:

async function getInfo() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

getInfo().then(data => console.log(data));

await关键字必须出现在async函数中
async函数中多个await执行顺序是串行的
await后面跟的是什么?一般是Promise实例对象,也可以是普通数据
async函数返回值是Promise实例对象
async函数中依然可以调用async函数

3.2. async/await 和 Promise 的关系

function showInfo () {
  return 'hello'
}

function queryData () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('nihao')
    }, 2000)
  })
}

// async函数的返回值是什么?Promise实例对象
async function getResult () {
  // 异步任务执行结束后可以得到结果
  // await后面跟的是什么?Promise实例对象
  // await接收的值是异步的结果
  let ret = await queryData()
  // await后面如果是普通数据也是可以的
  // let ret1 = await showInfo()
  // console.log(ret)
  // console.log(ret1)
  return ret
  // return new Promise((resolve, reject) => {
  //   resolve(ret)
  // })
}

// let result = getResult()
// result.then(ret => {
//   console.log(ret)
// })


// async函数中依然可以调用async函数
async function testData () {
  
  getResult().then(res => {
    console.log(res)
  })

  // let info = await getResult()
  // console.log(info)
}

testData()

3.3. async/await 的错误处理方法

Async/await 也可以与 try/catch 块一起使用来处理错误。这是一个例子:

async function getInfo() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error(error);
  }
}

getInfo();

4. Generator

4.1. Generator 的基本概念和使用方法

function*()是ES6中引入的一种新的函数类型,也被称为生成器函数。它是一种特殊的函数,可以在执行过程中暂停和恢复。在生成器函数中,可以使用yield关键字来暂停函数执行,并返回一个值。然后,可以再次调用生成器函数以恢复函数执行,并继续执行yield之后的代码。

以下是一个简单的生成器函数的示例:

function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = generateSequence();

console.log(generator.next().value); // 输出 1
console.log(generator.next().value); // 输出 2
console.log(generator.next().value); // 输出 3

在这个例子中,generateSequence函数是一个生成器函数,它使用yield关键字来暂停函数执行。在generateSequence函数中,我们依次返回1、2和3。然后,我们创建一个生成器对象generator,并使用next()方法来执行生成器函数的下一个步骤。

在第一次调用generator.next()时,函数执行到第一个yield关键字,暂停函数执行,并返回值1。在第二次调用generator.next()时,函数从上次暂停的地方继续执行,并执行到第二个yield关键字,暂停函数执行,并返回值2。在第三次调用generator.next()时,函数从上次暂停的地方继续执行,并执行到最后一个yield关键字,暂停函数执行,并返回值3。

生成器函数可以接受参数,并根据参数来控制函数执行。以下是一个带参数的生成器函数的示例:

function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}

const generator = generateSequence(1, 3);

console.log(generator.next().value); // 输出 1
console.log(generator.next().value); // 输出 2
console.log(generator.next().value); // 输出 3

在这个例子中,generateSequence函数接受两个参数startend,并使用for循环生成从startend的数字序列。然后,我们创建一个生成器对象generator,并使用next()方法来执行生成器函数的下一个步骤。

在第一次调用generator.next()时,函数执行到for循环的第一个步骤,生成1并暂停函数执行。在第二次调用generator.next()时,函数从上次暂停的地方继续执行,生成2并暂停函数执行。在第三次调用generator.next()时,函数从上次暂停的地方继续执行,生成3并暂停函数执行。

生成器函数可以与其他函数结合使用,以创建简单的迭代器。以下是一个使用生成器函数实现的迭代器的示例:

function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}

function iterateSequence(sequence) {
  const iterator = sequence[Symbol.iterator]();
  console.log(iterator, "iterator");

  while (true) {
    const result = iterator.next();
    console.log(result); 
    // result: { value: 1, done: false } { value: 2, done: false } { value: 3, done: false } { value: undefined, done: true }
    if (result.done) {
      break;
    }

    console.log(result.value);
  }
}

// 执行生成器函数
const sequence = generateSequence(1, 3);

// 执行迭代器函数
iterateSequence(sequence);

// 最终输出 1  2  3

在这个例子中,我们定义了一个iterateSequence函数,它接受一个可迭代序列,并使用while循环遍历序列中的所有元素。在iterateSequence函数中,我们使用sequence[Symbol.iterator]()获取序列的迭代器,并使用iterator.next()来获取序列中的下一个元素。如果result.donetrue,则表示序列中没有更多的元素可供遍历,我们就可以退出循环了。

最后,我们创建了一个生成器对象sequence,并将其传递给iterateSequence函数,以遍历序列中的所有元素。

生成器函数是一种很有用的函数类型,在处理迭代器和异步操作时非常有用。

4.2. Generator 和异步编程的结合

生成器可以与异步编程结合使用,以简化和优化异步代码。通过使用生成器来控制异步操作的流程,您可以编写看起来和表现得更像同步代码的异步代码。

以下是使用生成器来控制异步操作流程的示例:

function fetchData(url) {
  return fetch(url)
    .then(response => response.json())
}

function* fetchMultipleData() {
  // 模拟接口调用
  const data1 = yield fetchData('https://api.example.com/data1');
  const data2 = yield fetchData('https://api.example.com/data2');
  const data3 = yield fetchData('https://api.example.com/data3');
  // 返回接口拿回来的数据
  return [data1, data2, data3];
}

function run() {
  const generator = fetchMultipleData();
  let promise = generator.next().value;
  
  // done为true的时候退出迭代
  while (!generator.next(promise).done) {
    promise = promise.then(data => generator.next(data).value);
  }

  promise.then(result => console.log(result));
}

run();

在此示例中,fetchData是一个函数,它返回一个 Promise,该 Promise 解析为使用 fetch API 从 URL 检索的 JSON 数据。fetchMultipleData是一个生成器函数,它使用 yield 暂停执行并等待每个异步操作完成后继续。当所有异步操作完成时,fetchMultipleData 返回一个结果数组。

run 函数负责运行生成器。它创建生成器的新实例,使用 generator.next().value 获取第一个 Promise,然后进入一个循环,直到生成器完成。在循环的每次迭代中,它使用 generator.next(data).value 获取下一个 Promise,其中 data 是上一个异步操作的结果。然后继续下一次循环迭代,将新的 Promise 传递给 generator.next(promise).done。最后,它将已完成的异步操作的结果记录在控制台中。

4.3. Generator 的错误处理方法

使用生成器时,可以在生成器函数内部使用try/catch块来处理错误。以下是一个示例:

function* myGenerator() {
  try {
    yield 1;
    yield 2;
    throw new Error('出现问题了!');
    yield 3;
  } catch (error) {
    console.error(error);
  }
}

const generator = myGenerator();

console.log(generator.next().value); // 输出:1
console.log(generator.next().value); // 输出:2
console.log(generator.next().value); // 输出:日志中记录的错误
console.log(generator.next().value); // 输出:undefined

在这个示例中,myGenerator函数定义了一个生成器,它产生了三个值,然后抛出一个错误。在生成器函数内部,我们将yield语句包装在try块中,并使用catch块捕获任何错误。当抛出错误时,catch块将错误记录到控制台。

然后,我们创建了一个生成器对象generator,并使用它的next()方法迭代生成器产生的值。前两次调用generator.next()返回前两个产生的值,而第三次调用将错误记录到控制台。第四次调用generator.next()返回undefined,因为生成器函数已经执行完毕。

还可以通过将生成器包装在try/catch块中来在生成器函数外部处理错误。以下是一个示例:

function* myGenerator() {
  yield 1;
  yield 2;
  throw new Error("出现问题了!");
  yield 3;
}

try {
  const generator = myGenerator();
  console.log(generator.next().value); // 输出:1
  console.log(generator.next().value); // 输出:2
  console.log(generator.next().value); // 输出:抛出错误
  console.log(generator.next().value); // 不会输出,执行已经结束了
} catch (error) {
  console.error(error);
}

在这个示例中,我们将整个生成器函数包装在try/catch块中。当生成器函数内部抛出错误时,由函数外部的catch块捕获,并将错误记录到控制台。

处理生成器中的错误非常重要,以确保意外错误不会导致程序崩溃。

5. 其他异步编程技术

5.1. 事件监听器

事件监听器是JavaScript中的一种强大工具,它允许您响应浏览器中发生的特定事件。要添加事件监听器,首先需要选择要侦听事件的元素,例如使用getElementByIdquerySelectorquerySelectorAll等方法。一旦您获得了元素的引用,就可以调用addEventListener方法,传递你想要侦听的事件类型(例如clickmouseoversubmit),以及在事件发生时要调用的函数。

以下是向按钮元素添加单击事件监听器的示例:

const myButton = document.getElementById('my-button');

myButton.addEventListener('click', function() {
  console.log('Button clicked!');
});

还可以通过使用querySelectorAll方法选择一组元素,然后循环遍历它们以向每个元素添加事件监听器,从而一次性向多个元素添加事件监听器。

const allButtons = document.querySelectorAll('button');

for (let i = 0; i < allButtons.length; i++) {
  allButtons[i].addEventListener('click', function() {
    console.log('Button clicked!');
  });
}

5.2. setInterval 和 setTimeout

setTimeout允许你在指定的时间后执行一段代码。 setTimeout的语法如下:

setTimeout(function, milliseconds);

function参数是要执行的函数,milliseconds参数是在执行函数之前要等待的时间(以毫秒为单位)。

例如,以下代码将在页面加载完成后3秒将 Hello, world! 记录到控制台:

setTimeout(function() {
  console.log("Hello, world!");
}, 3000);

setInterval类似于setTimeout,但是它将在指定的间隔重复执行代码。

setInterval的语法如下:

setInterval(function, milliseconds);

function参数是要执行的函数,milliseconds参数是每次执行函数之间要等待的时间(以毫秒为单位)。

例如,以下代码将每秒将当前时间记录到控制台:

setInterval(function() {
  console.log(new Date().toLocaleTimeString());
}, 1000);

setTimeoutsetInterval都是在JavaScript应用程序中创建基于时间的功能的有用工具。 但是,重要的是要小心使用它们,并避免在用户设备上创建过多的负载。

6. 异步编程的最佳实践

6.1. 如何优化异步编程性能

优化异步编程性能的几种方法:

  1. 避免回调地狱:回调地狱是指多层嵌套的回调函数,会使代码难以阅读和维护。可以使用 Promiseasync/await 来避免回调地狱。
  2. 合并请求:在发送多个异步请求时,可以将它们合并为一个请求,以减少网络流量和请求次数
  3. 缓存数据:如果可能的话,可以缓存已检索的数据,以避免重复检索。
  4. 控制并发:如果多个异步操作需要同时进行,可以使用 Promise.all 或其他类似的方法来控制并发数量,以避免过多的负载。
  5. 使用 Web WorkersWeb Workers 允许在后台线程中运行 JavaScript 代码,以避免阻塞 UI 线程。
  6. 优化 I/O 操作:使用流和缓冲区来优化 I/O 操作,以减少内存使用和提高性能。
  7. 减少 DOM 操作:DOM 操作通常很慢,可以使用虚拟 DOM 或其他技术来减少 DOM 操作数量和频率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/734766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库中对表进行创建,插入数据并对数据进行选择

目录 1.根据此图进行建表并插入数据 2.对表进行以下操作 a:显示所有职工的基本信息 b:查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号 c:求出所有职工的人数 d:列出最高工和最低工资 e:列出职工的平均工资和总工资 f:创建一个只有职工号、姓名和参加工作的…

123.HTML5+CSS3完结_使用Netlify收取表单

Netlify也可以做表单接受&#xff1a; 我们启动一下 修改下表单 ● 接着在我们的网站输入并提交表单 ● 之后会有一个提示&#xff0c;提示我们提交成功 然后就能在Netlify接受到用户的表单 ● 当然这个表单只能接受100个&#xff0c;但是作为实验也够用了 到此&a…

文字磨练课程:提高编辑和校对效率的方法

提高编辑和校对效率&#xff0c;可以使你更有效地完成写作任务&#xff0c;提升文章质量。以下是一些方法&#xff0c;可以帮助你在编辑和校对过程中提高效率。 1.设定目标和计划 在开始编辑和校对前&#xff0c;设定明确的目标和计划。这可以帮助你集中注意力&#xff0c;提…

【SQL应知应会】表分区(一)• MySQL版

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 分区表 • MySQL版 一、分区表1.非分区表2.分区表2…

整齐有序!统一命名文件,高效管理数据轻松实现!

在数字化时代&#xff0c;我们每天都与大量文件打交道&#xff0c;文件名杂乱无章、难以辨识的情况是司空见惯的。这不仅浪费我们宝贵的时间&#xff0c;还可能导致信息混乱和数据丢失。但是&#xff0c;抛开这一切困扰吧&#xff01;现在&#xff0c;我们向您介绍一个简单却强…

C++—string类

本期我们来学习C的string&#xff0c;本期内容相当的多&#xff0c;且有一定难度&#xff0c;需要大家静下心来看 目录 1.标准库中的string 1.1string类的介绍 1.2 string类的常用接口 构造函数、析构函数、赋值、拷贝构造 npos push_back append operator[ ] size …

什么是ASPICE认证

ASPICE&#xff1a; “AutomotiveSoftware ProcessImprovement and CapacityDetermination”&#xff0c;即汽车软件过程改进及能力评定。它是一个过程模型&#xff0c;由过程和能力度两个维度构成&#xff0c;用于评价汽车行业软件设计开发的能力水平。 ASPICE的6个级别&…

基于simulink进行场景变化检测(附源码)

一、前言 此示例演示如何及时分割视频。此示例中的算法可用于检测视频流中的重大变化&#xff0c;例如广告开始和结束的时间。场景变换在广告和营销中被广泛应用。通过改变场景&#xff0c;可以吸引消费者的注意力&#xff0c;传达产品或服务的特点和优势。例如&#xff0c;将…

包揽七项葵花奖 参编多项标准 萤石领跑智能家居+物联网云平台行业

7月9日&#xff0c;2023第七届“葵花奖”智能家居评选颁奖盛典在广交会展馆举行&#xff0c;萤石网络一举斩获7项重磅奖项。同时&#xff0c;萤石作为参编单位&#xff0c;受邀参与了《智能门锁测评标准》发布仪式及《智能开关测评标准》启动会&#xff0c;再次彰显了其在智能家…

【一些随笔】浅析 Linux和Windows:系统介绍、操作差异与使用技巧解析

一些随笔 文章内容1️⃣ 那些在Linux上顺理成章&#xff0c;换到Windows上就可能令人费解的事2️⃣ Linux系统介绍及使用技巧3️⃣ Windows系统介绍及使用技巧 文章内容 Linux和Windows系统的操作差异&#xff1b;Linux系统介绍、系统监控和优化技巧、Shell脚本编程技巧、一些…

掌握Python文件操作的绝招:打造数据之径,揭开文件操作的神秘面纱

文章目录 前言文件的基本操作打开文件操作关闭文件操作对文件进行操作1&#xff09;只读文件操作read()readlines()readline()seek() 2&#xff09;只写文件操作3&#xff09;文件追加操作读写、追加读写操作1. r 模式打开文件2. w 模式打开文件3. a 模式打开文件 以二进制的形…

走向 Native 化:SpringDubbo AOT 技术示例与原理讲解

作者&#xff1a;刘军 Java 应用在云计算时代面临“冷启动”慢、内存占用高、预热时间长等问题&#xff0c;无法很好的适应 Serverless 等云上部署模式&#xff0c;GraalVM 通过静态编译、打包等技术在很大程度上解决了这些问题&#xff0c;同时针对 GraalVM 的一些使用限制&a…

用了国产接口管理神器 Apifox 之后,我果断从 Postman “脱坑”了

在当前行业发展背景下&#xff0c;绝大部分项目都是基于前后端分离的架构进行的&#xff0c;由前后端、测试、运维等不同的团队共同开发&#xff0c;那么团队之间能否很好的 协同合作 无疑直接决定着项目的最终效果。 但是在实际开发流程中&#xff0c;团队之间的协同是很低效…

网络编程5——TCP协议的五大效率机制:滑动窗口+流量控制+拥塞控制+延时应答+捎带应答

文章目录 前言一、TCP协议段与机制TCP协议的特点TCP报头结构TCP协议的机制与特性 二、TCP协议的 滑动窗口机制 三、TCP协议的 流量控制机制 四、TCP协议的 拥塞控制机制 五、TCP协议的 延时应答机制 六、TCP协议的 捎带应答机制 总结 前言 本人是一个普通程序猿!分享一点自己的…

c语言进阶-printf的用法拓展

Printf函数打印方法拓展&#xff1a; 字符串赋值给指针&#xff0c;相当于把h的地址赋值给p了。 printf函数直接放字符串也是把首地址给printf&#xff0c;然后printf从首地址打印到\0。 打印时可以直接传p地址

IDEA使用教程

1. 查看代码历史版本 若要查看特定 Java 类的代码历史版本&#xff0c;请执行以下操作&#xff1a; 鼠标右键点击所需查看的 Java 类。 在弹出菜单中选择 "Local History"&#xff08;本地历史&#xff09; >> "Show History"&#xff08;显示历史…

云尚办公项目-搭建环境

硅谷项目&#xff0c;由尚硅谷分享&#xff0c;具体项目视频可以根据B站尚硅谷进行学习。搭建项目可以直接根据Spring Boot进行获取&#xff0c;本次主要是个人的的一些分析操作 后面代码主要以分析为主&#xff0c;相关内容不会的&#xff0c;可以观看尚硅谷视频 一、下载配套…

MySQL数据库——多表查询练习

一、练习素材 创建表 -- 创建部门表 create table if not exists dept3( deptno varchar(20) primary key , -- 部门号 name varchar(20) -- 部门名字 );-- 创建员工表 create table if not exists emp3( eid varchar(20) primary key , -- 员工编号 ename varchar(20), -- 员…

【雕爷学编程】Arduino动手做(153)---2.4寸TFT液晶触摸屏模块6

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

详解c++---布隆过滤器

目录标题 位图的优缺点为什么会有布隆过滤器&#xff1a;布隆过滤器的应用场景&#xff1a;布隆过滤器的实现布隆过滤器的测试 位图的优缺点 位图的优点&#xff1a; 1.位图可以节省空间&#xff0c;位图判断存储的数据是在还是不在只用一个比特位就可以记录数据出现的情况&a…