>  기사  >  웹 프론트엔드  >  JavaScript의 콜백 함수에 대한 심층 분석(동기 및 비동기)

JavaScript의 콜백 함수에 대한 심층 분석(동기 및 비동기)

青灯夜游
青灯夜游앞으로
2022-08-04 10:05:193815검색

콜백 함수는 모든 프론트엔드 프로그래머가 알아야 할 개념 중 하나입니다. 콜백은 배열, 타이머 함수, 약속 및 이벤트 처리에 사용될 수 있습니다. 이 문서에서는 콜백 함수의 개념을 설명하고 두 가지 유형의 콜백(동기 및 비동기)을 구별하는 데 도움을 줍니다.

JavaScript의 콜백 함수에 대한 심층 분석(동기 및 비동기)

1. 콜백 함수

먼저 인사하는 함수를 작성하세요.

name 매개변수를 허용하는 greet(name) 함수를 만드세요. 이 함수는 다음과 같은 인사말 메시지를 반환해야 합니다. name 参数的函数 greet(name)。这个函数应返回打招呼的消息:

function greet(name) {
  return `Hello, ${name}!`;
}

greet('Cristina'); // => 'Hello, Cristina!'

如果向很多人打招呼该怎么办?可以用特殊的数组方法  array.map() 可以实现:

const persons = ['Cristina', 'Ana'];

const messages = persons.map(greet);
messages; // => ['Hello, Cristina!', 'Hello, Ana!']

persons.map(greet) 获取 persons 数组的所有元素,并分别用每个元素作为调用参数来调用 greet() 函数:`greet('Cristina'), greet('Ana')

有意思的是 persons.map(greet) 方法可以接受 greet()  函数作为参数。这样 greet()  就成了回调函数

persons.map(greet) 是用另一个函数作为参数的函数,因此被称为高阶函数

回调函数作为高阶函数的参数,高阶函数通过调用回调函数来执行操作。

重要的是高阶函数负责调用回调,并为其提供正确的参数。

在前面的例子中,高阶函数 persons.map(greet) 负责调用  greet()  函数,并分别把数组中所有的元素 'Cristina'Ana ' 作为参数。

这就为识别回调提供了一条简单的规则。如果你定义了一个函数,并将其作参数提供给另一个函数的话,那么这就创建了一个回调。

你可以自己编写使用回调的高阶函数。下面是 array.map() 方法的等效版本:

function map(array, callback) {
  const mappedArray = [];
  for (const item of array) { 
    mappedArray.push(
      callback(item)    );
  }
  return mappedArray;
}

function greet(name) {
  return `Hello, ${name}!`;
}

const persons = ['Cristina', 'Ana'];

const messages = map(persons, greet);messages; // => ['Hello, Cristina!', 'Hello, Ana!']

map(array, callback) 是一个高阶函数,因为它用回调函数作为参数,然后在其主体内部调用该回调函数:callback(item)

注意,常规函数(用关键字 function 定义)或箭头函数(用粗箭头 => 定义)同样可以作为回调使用。

2、同步回调

回调的调用方式有两种:同步异步回调。

同步回调是“阻塞”的:高阶函数直到回调函数完成后才继续执行。

例如,调用 map()greet() 函数。

function map(array, callback) {
  console.log('map() starts');
  const mappedArray = [];
  for (const item of array) { mappedArray.push(callback(item)) }
  console.log('map() completed');
  return mappedArray;
}

function greet(name) {
  console.log('greet() called');
  return `Hello, ${name}!`;
}

const persons = ['Cristina'];

map(persons, greet);
// logs 'map() starts'
// logs 'greet() called'
// logs 'map() completed'

其中 greet()  是同步回调。

同步回调的步骤:

  • 高阶函数开始执行:'map() starts'

  • 回调函数执行:'greet() called'

  • .最后高阶函数完成它自己的执行过程:'map() completed'

同步回调的例子

许多原生 JavaScript 类型的方法都使用同步回调。

最常用的是 array 的方法,例如: array.map(callback), array.forEach(callback), array.find(callback), array.filter(callback), array.reduce(callback, init)

// Examples of synchronous callbacks on arrays
const persons = ['Ana', 'Elena'];

persons.forEach(
  function callback(name) {    console.log(name);
  }
);
// logs 'Ana'
// logs 'Elena'

const nameStartingA = persons.find(
  function callback(name) {    return name[0].toLowerCase() === 'a';
  }
);
nameStartingA; // => 'Ana'

const countStartingA = persons.reduce(
  function callback(count, name) {    const startsA = name[0].toLowerCase() === 'a';
    return startsA ? count + 1 : count;
  }, 
  0
);
countStartingA; // => 1

字符串类型的 string.replace(callback)  方法也能接受同步执行的回调:

// Examples of synchronous callbacks on strings
const person = 'Cristina';

// Replace 'i' with '1'
person.replace(/./g, 
  function(char) {    return char.toLowerCase() === 'i' ? '1' : char;
  }
); // => 'Cr1st1na'

3、异步回调

异步回调是“非阻塞的”:高阶函数无需等待回调完成即可完成其执行。高阶函数可确保稍后在特定事件上执行回调。

在以下的例子中,later() 函数的执行延迟了 2 秒:

console.log('setTimeout() starts');
setTimeout(function later() {
  console.log('later() called');
}, 2000);
console.log('setTimeout() completed');

// logs 'setTimeout() starts'
// logs 'setTimeout() completed'
// logs 'later() called' (after 2 seconds)

later() 是一个异步回调,因为 setTimeout(later,2000) 启动并完成了执行,但是 later() 在 2 秒后执行。

异步调用回调的步骤:

  • 高阶函数开始执行:'setTimeout()starts'

  • 高阶函数完成其执行: 'setTimeout() completed'

  • 回调函数在 2 秒钟后执行: 'later() called'

异步回调的例子

计时器函数异步调用回调:

setTimeout(function later() {
  console.log('2 seconds have passed!');
}, 2000);
// After 2 seconds logs '2 seconds have passed!' 

setInterval(function repeat() {
  console.log('Every 2 seconds');
}, 2000);
// Each 2 seconds logs 'Every 2 seconds!'

DOM 事件侦听器还异步调用事件处理函数(回调函数的子类型):

const myButton = document.getElementById('myButton');

myButton.addEventListener('click', function handler() {
  console.log('Button clicked!');
});
// Logs 'Button clicked!' when the button is clicked

4、异步回调函数与异步函数

在函数定义之前加上特殊关键字 async

async function fetchUserNames() {
  const resp = await fetch('https://api.github.com/users?per_page=5');
  const users = await resp.json();
  const names = users.map(({ login }) => login);
  console.log(names);
}
많은 사람에게 인사하면 어떻게 되나요? 특수 배열 메소드 array.map()을 사용하여 다음을 달성할 수 있습니다. 🎜
const button = document.getElementById('fetchUsersButton');

button.addEventListener('click', fetchUserNames);
🎜persons.map(greet) persons의 모든 요소 가져오기 > 배열을 사용하고 각 요소를 호출 매개변수로 사용하여 greet() 함수를 호출합니다. `greet('Cristina'), greet('Ana'). 🎜🎜흥미롭게도 <code>persons.map(greet) 메서드는 greet() 함수를 매개변수로 받아들일 수 있습니다. 이런 식으로 greet()는 🎜콜백 함수🎜가 됩니다. 🎜🎜persons.map(greet)는 다른 함수를 매개변수로 받는 함수이므로 🎜고차 함수🎜라고 합니다. 🎜
콜백 함수고차 함수의 매개변수로 사용되며, 고차 함수는 콜백 함수를 호출하여 연산을 수행합니다.
🎜중요한 것은 고차 함수가 콜백을 호출하고 올바른 매개변수를 제공하는 역할을 한다는 것입니다. 🎜🎜이전 예에서 고차 함수 persons.map(greet)greet() 함수를 호출하고 배열 ' Cristina' 및 Ana '를 매개변수로 사용합니다. 🎜🎜이는 콜백을 식별하는 간단한 규칙을 제공합니다. 함수를 정의하고 이를 다른 함수에 매개변수로 제공하면 콜백이 생성됩니다. 🎜🎜콜백을 사용하여 자신만의 고차 함수를 작성할 수 있습니다. 다음은 array.map() 메서드의 해당 버전입니다. 🎜rrreee🎜map(array, callback)은 콜백 함수를 다음과 같이 사용하므로 고차 함수입니다. 매개변수, 콜백 함수는 본문(callback(item)) 내부에서 호출됩니다. 🎜🎜일반 함수(function 키워드로 정의됨) 또는 화살표 함수(굵은 화살표 =>로 정의됨)도 콜백으로 사용할 수 있습니다. 🎜🎜🎜2. 동기 콜백 🎜🎜🎜콜백 방법에는 🎜동기🎜 및 🎜비동기🎜콜백 두 가지가 있습니다. 🎜🎜동기식 콜백은 "차단"됩니다. 고차 함수는 콜백 함수가 완료될 때까지 실행을 계속하지 않습니다. 🎜🎜예를 들어 map()greet() 함수를 호출하세요. 🎜rrreee🎜여기서 greet()는 동기 콜백입니다. 🎜🎜동기 콜백 단계: 🎜
  • 🎜고차 함수 실행 시작: 'map() start'🎜 li >
  • 🎜콜백 함수 실행: 'greet() 호출됨'🎜
  • 🎜 마지막으로 고차 함수는 자체 실행 프로세스를 완료합니다: ' map() 완료됨'🎜

🎜동기 콜백의 예🎜

🎜많은 기본 JavaScript 유형 메서드는 동기 콜백을 사용합니다. 🎜🎜가장 일반적으로 사용되는 방법은 배열입니다. 예: array.map(callback), array.forEach(callback), array.find(callback) , array.filter(callback), array.reduce(callback, init)🎜rrreee🎜string.replace(callback) 이 메서드는 동기적으로 실행되는 콜백도 허용할 수 있습니다. 🎜rrreee🎜🎜3. 비동기 콜백 🎜🎜🎜비동기 콜백은 "비차단"입니다. 고차 함수는 콜백이 완료될 때까지 기다리지 않고 실행을 완료할 수 있습니다. 고차 함수는 나중에 특정 이벤트에서 콜백이 실행되도록 보장합니다. 🎜🎜다음 예에서는 <code>later() 함수의 실행이 2초 지연됩니다. 🎜rrreee🎜later()setTimeout이므로 비동기 콜백입니다. (나중, 2000)은 실행을 시작하고 완료하지만 later()는 2초 후에 실행됩니다. 🎜🎜콜백을 비동기식으로 호출하는 단계: 🎜
  • 🎜고차 함수 실행 시작: 'setTimeout()starts'🎜 li>
  • 🎜고차 함수 실행 완료: 'setTimeout() 완료'🎜
  • 🎜콜백 함수는 2초 후에 실행됩니다: 'later( ) 호출됨'🎜

🎜비동기 콜백의 예🎜

🎜Timer 함수는 콜백을 비동기적으로 호출합니다.🎜rrreee🎜DOM 이벤트 리스너는 이벤트 핸들러도 호출합니다. 비동기 함수(콜백 함수의 하위 유형): 🎜rrreee🎜🎜4. 비동기 콜백 함수 및 비동기 함수 🎜🎜🎜 함수 정의 앞에 특수 키워드 async를 추가하면 비동기 함수가 생성됩니다. 🎜
async function fetchUserNames() {
  const resp = await fetch('https://api.github.com/users?per_page=5');
  const users = await resp.json();
  const names = users.map(({ login }) => login);
  console.log(names);
}

fetchUserNames() 是异步的,因为它以 async 为前缀。函数  await fetch('https://api.github.com/users?per_page=5') 从 GitHub 上获取前5个用户 。然后从响应对象中提取 JSON 数据:await resp.json()

异步函数是 promise 之上的语法糖。当遇到表达式 await <promise>  (调用  fetch()  会返回一个promise)时,异步函数会暂停执行,直到 promise 被解决。

异步回调函数和异步函数是不同的两个术语。

异步回调函数由高阶函数以非阻塞方式执行。但是异步函数在等待 promise(await <promise>)解析时会暂停执行。

但是你可以把异步函数用作异步回调!

让我们把异步函数 fetch UserNames() 设为异步回调,只需单击按钮即可调用:

const button = document.getElementById('fetchUsersButton');

button.addEventListener('click', fetchUserNames);

总结

回调是一个可以作为参数传给另一个函数(高阶函数)执行的函数。

回调函数有两种:同步和异步。

  • 同步回调是阻塞的。

  • 异步回调是非阻塞的。

【相关推荐:javascript学习教程

위 내용은 JavaScript의 콜백 함수에 대한 심층 분석(동기 및 비동기)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제