Предварительное объяснение принципа обратного вызова обратного вызова в JS

JavaScript

Механизм асинхронного выполнения JS

Что такое асинхронное выполнение

Чтобы повысить эффективность выполнения кода Javascript, JS использует механизм асинхронного вызова (например, операцию Ajax) для некоторых методов функций. Выполнение асинхронно выполняемых методов функции не выполняется один за другим для очереди, а независимо друг от друга и вызывается и выполняется одновременно, что позволяет избежать блокировки выполнения кода и сократить ненужное время ожидания.

异步执行机制

Возьмем каштан

Когда большинство новичков программируют, они разрабатывают код в соответствии с методом линейного мышления, который конфликтует с механизмом асинхронного выполнения в JS.

Такие как: Мы надеемся назначить строку в файле чтения в переменную после операции чтения потока документа.strЗатем послеconsole.log()Метод выводит содержимое прочитанного файла.В это время, если мы разработаем код в соответствии с нашим линейным мышлением, будут написаны следующие операции:

// 需求:封装一个方法,传入一个路径,可以读取相对应的文件
const fs = require('fs');
const path = require('path');

// 给定文件路径,返回读取到的内容
function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      var str = dataStr;
    }
  })
}

// 调用读取文件方法
getFileByPath(path.join(__dirname, './files/1.txt'));

console.log(str);

Результат вывода консоли

ReferenceError: str is not defined

Это потому, что мы рассматриваем проблему в соответствии с линейным мышлением и считаем само собой разумеющимся, что переменнаяstrОпределение и назначение вconsole.log()console.log(),for循环

var test = function () {
  console.log('1');
}
test();

for (var i = 2; i < 5; i++) {
  console.log(i);
}

console.log('6');

Результат вывода консоли

1 2 3 4 5 6

Однако операция чтения файла — это операция, которая приведет к блокировке кода, поэтому JS поместит его в асинхронную очередь и выполнит код позади, поэтому правильный порядок выполнения кода в каштане должен быть выполнен первым.console.log()повторно выполнитьgetFileByPath().

Перезвоните

Так что, если нам просто нужно иметь пошаговую операцию и выполнять ее после чтения файла, вместо того, чтобы пропускать операцию чтения файла и выполнять ее напрямую?

Это требует идеи «функций обратного вызова», чтобы спасти нас. Большинство людей знают, что функции обратного вызоваjQueryОднако новички часто мало знают о принципе функции обратного вызова, поэтому мы все же будем использовать этот каштан в качестве представителя для обсуждения функции обратного вызова.

Давайте сначала отложим в сторону функцию обратного вызова и воспользуемся самым примитивным методом, позволяющим выполнять некоторые операции после операции чтения файла. То есть напрямую переписать весьgetFileByPath()метод:

// 需求:封装一个方法,传入一个路径,可以读取相对应的文件
const fs = require('fs');
const path = require('path');

// 给定文件路径,返回读取到的内容
function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      var str = dataStr;
+	    console.log(str);
    }
  })
}

// 调用读取文件方法
getFileByPath(path.join(__dirname, './files/1.txt'));

Так что мы можем идти прямоgetFileByPathПосле метода содержимое прочитанного файла выводится в консоль. Но такая операция не может решить нашу проблему очень хорошо.Если метод инкапсулирован и используется другими, другим людям необходимо изменить исходный код, чтобы реализовать функциональный метод.Очевидно, что это не является гибким, и это даже изменит оригинальный метод метода Функция.

Итак, нам нужно установить функцию обратного вызова после завершения асинхронной операции, а затем выполнить следующий шаг в наших нуждах.

Для того, чтобы понять принцип работы callback-функции, сначала разделим эту часть кода после изменения:

if (err)
      throw err;
    else {
      var str = dataStr;
+     console.log(str);
    }

Видно, что прочитав файл, он пойдет прямоelseСледующая операция, если положитьvar str = dataStr; console.log(str)clgЧто мыelseПосле выполненияclg()

function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      clg(dataStr);
    }
  })
}

function clg(dataStr){
	var str = dataStr;
	console.log(str);
}

getFileByPath(path.join(__dirname, './files/1.txt'));

Таким образом, мы можем поместить операции, выполняемые после операции чтения файла, вclgметод может быть выполнен, этоclg()

Давайте посмотрим на функцию обратного вызова jQuery:

$('#demo').animate({"opacity":"1"}, 1000, fucntion(){... функция обратного вызова ..});

jQuery передает функцию обратного вызова в качестве параметра метода, поэтому нам просто нужноgetFileByPath()Добавьте параметр в метод, этот параметр является функцией, мы можем добавить параметр в исходный кодelseПосле выполнения переданной функции эта функция называется «функцией обратного вызова».

ПереписаноgetFileByPath()метод

function getFileByPath(fpath, callback) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      callback(dataStr);
    }
  })
}

После этого, когда будем вызывать, пропишем в параметре бит функцию метода, и этот метод будет передан вgetFileByPath()Внутри метода дождитесь завершения операции чтения файла, прежде чем идти прямо.

getFileByPath(path.join(__dirname, './files/1.txt'), function(dataStr){
	var str = dataStr;
	console.log(str);
});

Стоит отметить, что когда мы устанавливаем бит входящего параметра в исходном коде, мы устанавливаем параметр функции обратного вызова

callback(dataStr);

этоdataStrЧтение содержимого файла — это операция чтения файла, мы будем передавать переменныеcallback()getFileByPath()dataStr

Это простое объяснение функции обратного вызова, новые программисты, добро пожаловать на исправления- ̗̀(๑ᵔ⌔ᵔ๑)

Механизм асинхронного выполнения JS

Что такое асинхронное выполнение

Чтобы повысить эффективность выполнения кода Javascript, JS использует механизм асинхронного вызова (например, операцию Ajax) для некоторых методов функций. Выполнение асинхронно выполняемых методов функции не выполняется один за другим для очереди, а независимо друг от друга и вызывается и выполняется одновременно, что позволяет избежать блокировки выполнения кода и сократить ненужное время ожидания.

异步执行机制

Возьмем каштан

Когда большинство новичков программируют, они разрабатывают код в соответствии с методом линейного мышления, который конфликтует с механизмом асинхронного выполнения в JS.

Например: в узле мы хотим присвоить строку в прочитанном файле переменной после операции чтения потока документа,strиспользовать его позжеconsole.log()Метод выводит содержимое прочитанного файла.В это время, если мы разработаем код в соответствии с нашим линейным мышлением, будут написаны следующие операции:

// 需求:封装一个方法,传入一个路径,可以读取相对应的文件
const fs = require('fs');
const path = require('path');

// 给定文件路径,返回读取到的内容
function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      var str = dataStr;
    }
  })
}

// 调用读取文件方法
getFileByPath(path.join(__dirname, './files/1.txt'));

console.log(str);

Результат вывода консоли

ReferenceError: str is not defined

Это потому, что мы рассматриваем проблему в соответствии с линейным мышлением и считаем само собой разумеющимся, что переменнаяstrОперации определения и присваиванияconsole.log()До операции, но реальная ситуация такова, что после парсинга JS операции, которые можно выполнить мгновенно, такие какconsole.log(),for循环Другие основные операции выполняются в соответствии с очередью, например:

var test = function () {
  console.log('1');
}
test();

for (var i = 2; i < 5; i++) {
  console.log(i);
}

console.log('6');

Результат вывода консоли

1 2 3 4 5 6

Однако операция чтения файла — это операция, которая приведет к блокировке кода, поэтому JS поместит его в асинхронную очередь и выполнит код позади, поэтому правильный порядок выполнения кода в каштане должен быть выполнен первым.console.log()повторно выполнитьgetFileByPath().

Перезвоните

Так что, если нам просто нужно иметь пошаговую операцию и выполнять ее после чтения файла, вместо того, чтобы пропускать операцию чтения файла и выполнять ее напрямую?

Это требует идеи «функций обратного вызова», чтобы спасти нас. Большинство людей знают, что функции обратного вызоваjQueryОднако новички часто мало знают о принципе функции обратного вызова, поэтому мы все же будем использовать этот каштан в качестве представителя для обсуждения функции обратного вызова.

Давайте сначала отложим в сторону функцию обратного вызова и воспользуемся самым примитивным методом, позволяющим выполнять некоторые операции после операции чтения файла. То есть напрямую переписать весьgetFileByPath()метод:

// 需求:封装一个方法,传入一个路径,可以读取相对应的文件
const fs = require('fs');
const path = require('path');

// 给定文件路径,返回读取到的内容
function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      var str = dataStr;
+	    console.log(str);
    }
  })
}

// 调用读取文件方法
getFileByPath(path.join(__dirname, './files/1.txt'));

Так что мы можем идти прямоgetFileByPathПосле метода содержимое прочитанного файла выводится в консоль. Но такая операция не может решить нашу проблему очень хорошо.Если метод инкапсулирован и используется другими, другим людям необходимо изменить исходный код, чтобы реализовать функциональный метод.Очевидно, что это не является гибким, и это даже изменит оригинальный метод метода Функция.

Итак, нам нужно установить функцию обратного вызова после завершения асинхронной операции, а затем выполнить следующий шаг в наших нуждах.

Для того, чтобы понять принцип работы callback-функции, сначала разделим эту часть кода после изменения:

if (err)
      throw err;
    else {
      var str = dataStr;
+     console.log(str);
    }

Видно, что прочитав файл, он пойдет прямоelseСледующая операция, если положитьvar str = dataStr; console.log(str)clgЧто мыelseПосле выполненияclg()

function getFileByPath(fpath) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      clg(dataStr);
    }
  })
}

function clg(dataStr){
	var str = dataStr;
	console.log(str);
}

getFileByPath(path.join(__dirname, './files/1.txt'));

Таким образом, мы можем поместить операции, выполняемые после операции чтения файла, вclgметод может быть выполнен, этоclg()По сути, это можно назвать callback-функцией, но это все равно сделает код громоздким.

Давайте посмотрим на функцию обратного вызова jQuery:

$('#demo').animate({"opacity":"1"}, 1000, fucntion(){... функция обратного вызова ..});

jQuery передает функцию обратного вызова в качестве параметра метода, поэтому нам просто нужноgetFileByPath()Добавьте параметр в метод, этот параметр является функцией, мы можем добавить параметр в исходный кодelseПосле выполнения переданной функции эта функция называется «функцией обратного вызова».

переписанныйgetFileByPath()метод

function getFileByPath(fpath, callback) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err)
      throw err;
    else {
      callback(dataStr);
    }
  })
}

После этого, когда будем вызывать, пропишем в параметре бит функцию метода, и этот метод будет передан вgetFileByPath()Внутри метода дождитесь завершения операции чтения файла, прежде чем идти прямо.

getFileByPath(path.join(__dirname, './files/1.txt'), function(dataStr){
	var str = dataStr;
	console.log(str);
});

Стоит отметить, что когда мы устанавливаем бит входящего параметра в исходном коде, мы устанавливаем параметр функции обратного вызова

callback(dataStr);

этоdataStrЧтение содержимого файла — это операция чтения файла, мы будем передавать переменныеcallback()В методе, в вызовеgetFileByPath()Его можно вызвать в функции обратного вызова, написанной, когдаdataStrэта переменная.

Это простое объяснение функции обратного вызова, новые программисты, добро пожаловать на исправления- ̗̀(๑ᵔ⌔ᵔ๑)