Жизнь разработчика JS непроста без понимания основ того, что такое обратные вызовы и обещания. Между ними очень небольшая разница.

Начнем с основ.

1. Что такое нотация (req, res) = ›{} в JS?

Это стрелочная функция ES6, эквивалентная function (req, res) {}. Подробнее о том, как поведениеthis внутри стрелочных функций, читайте здесь.

2. Что делает метод bind в JS?

Метод bind() создает новую функцию, при вызове которой ее ключевое слово this устанавливается равным предоставленному значению с заданной последовательностью аргументов, предшествующей любым, предоставленным при вызове новой функции.

(req, res) = ›{} также помогает привязать контекст. Прочтите это, чтобы использовать его в React здесь.

var Button = function(content) { 
  this.content = content;
};
Button.prototype.click = function() {
  console.log(this.content + ' clicked');
}

var myButton = new Button('OK');
myButton.click();

var looseClick = myButton.click;
looseClick(); // not bound, 'this' is not myButton - it is the global object

var boundClick = myButton.click.bind(myButton);
boundClick(); // bound, 'this' is myButton

Ответ:

OK clicked
undefined clicked
OK clicked

3. Что такое закрытие?

Замыкание - это внутренняя функция, которая имеет доступ к переменным внешней (включающей) функции - цепочке областей видимости. Замыкание имеет три цепочки областей видимости: оно имеет доступ к своей собственной области (переменные, определенные в фигурных скобках), оно имеет доступ к переменным внешней функции и имеет доступ к глобальным переменным.

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

Подробную информацию о закрытии можно найти здесь. Благодаря замыканиям, возможно каррирование методов.

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

function multiplier(a) {
  return function (b) {
    return a * b;
  }
}
let multiplyByTwo = multiplier(2);
console.log(multiplyByTwo(10))
// Prints 20
// *** Lets use ES6 for the above task *** //
let multiplier = (a) => {
  return (b) => {
    return a * b;
  }
}
let multiplyByTwo = multiplier(2);
console.log(multiplyByTwo(10))
// Prints 20

4. Что такое пряжа?

Когда-нибудь приходили к нам с установками для пряжи? Самый популярный менеджер пакетов JavaScript - это клиент npm, который обеспечивает доступ к более чем 300 000 пакетов в реестре npm. Но по мере роста размера кодовой базы и количества инженеров они столкнулись с проблемами согласованности, безопасности и производительности.

Yarn - это новый менеджер пакетов JavaScript, созданный Facebook, Google, Exponent и Tilde. Как видно из официального объявления, его цель - решить несколько проблем, с которыми эти команды столкнулись с npm, а именно:

  • установка пакетов была недостаточно быстрой / последовательной, и
  • были проблемы с безопасностью, поскольку npm позволяет пакетам запускать код при установке.

Yarn - это всего лишь новый клиент CLI, который извлекает модули из реестра npm. В самом реестре ничего не изменится - вы по-прежнему сможете получать и публиковать пакеты в обычном режиме.

Обратные вызовы или функции более высокого порядка

Теперь перейдем к обратным вызовам. Сначала это звучит очень тревожно, но это очень легко, если мы читаем и понимаем об этом. Отличное чтение, чтобы начать с основ об обратном вызове, - здесь. Рекомендую сначала прочитать.

Мы можем передать несколько параметров функции обратного вызова в зависимости от функции.

Пример, поясняющий приведенную выше строку:

function myFetchData(url, callback) { 
  makeNetworkCall( url, (response) => {
    if (response.success) {
      callback(response.data, nil)
    } else {
      callback(nil, response.error)
    }
  });
}
/* Imagine makeNetworkCall makes a get call to the url which it accepts as the first param. On executing the call, it fills its response in the second argument it takes */
let url = "https://jsonplaceholder.typicode.com/todos/1";
myFetchData(url, function(data, error) {
  if (error != nil) {
    console.log("data", data)
  } else {
    console.log("error", error)
  }
});

Мы бы выполнили указанную выше задачу с обещанием, приведенным ниже.

Обещания

// Here's how you create a promise:
var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

Конструктор обещания принимает один аргумент, обратный вызов с двумя параметрами, разрешение и отклонение. Сделайте что-нибудь в обратном вызове, возможно, асинхронно, затем вызовите resolve, если все сработало, в противном случае вызовите reject.

Как и throw в простом старом JavaScript, обычно, но не обязательно, отклонять с помощью объекта Error.

Вот как вы используете это обещание:

promise.then(function(result) {
  console.log(result); // "Stuff worked!"
}, function(err) {
  console.log(err); // Error: "It broke"
});

Что тогда за ".error" в обещаниях?

Как мы видели ранее, then() принимает два аргумента, один для успеха, другой для неудачи (или выполнить и отклонить, на языке обещаний):

get('supplyData.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.log("Failed!", error);
})

Теперь с .catch ()

get('supplyData.json').then(function(response) {
  console.log("Success!", response);
}).catch(function(error) {
  console.log("Failed!", error);
})

В catch() нет ничего особенного, это просто сахар для then(undefined, func), но он более читабельный. Обратите внимание, что два приведенных выше примера кода не ведут себя одинаково, последний эквивалентен:

get('supplyData.json').then(function(response) {
  console.log("Success!", response);
}).then(undefined, function(error) {
  console.log("Failed!", error);
})

Давайте выполним указанную выше функцию myFetchData (которую мы делали ранее с обратным вызовом) с обещанием.

let myFetchData = (url) => {
  return new Promise((resolve, reject) => {
    makeNetworkCall( url , (response) => {
      if (response.success) {
        resolve(response.data)
      } else {
        reject(response.error)
      }
    });
  })
}
/* Imagine makeNetworkCall makes a get call to the url which it accepts as the first param. On executing the call, it fills its response in the second argument it takes */
let url = "https://jsonplaceholder.typicode.com/todos/1";
myFetchData(url)
  .then(data) {
    console.log("data", data)
  }
  .catch(error) {
    console.log("error", error)
  }

Посмотрите, как обещания спасают нас от ада обратных вызовов в цепочках. Это заставляет нас осознать важность структуры и системы в нашей жизни! Теперь поговорим о цепочке в обещаниях. Допустим, мы хотим использовать полученные данные при вызове API и вызывать другую функцию с этими данными.

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

getJSON('supplyData.json').then(function(supply) {
  return supply[0];
}).then(function(supply0) {
  console.log("Got supply0!", supply0);
})

Давайте углубимся в цепочку.

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000); // (Zone 1)
  })
  .then(function(result) { // (Zone 2)
    alert(result); // 1
    return result * 2;
  })
  .then(function(result) { // (Zone 3)
    alert(result); // 2
    return result * 2;
  })
  .then(function(result) {
    alert(result); // 4
    return result * 2;
});

Все работает, потому что вызов promise.then возвращает обещание, так что мы можем вызвать для него следующий .then. В Зоне 2 возвращаемое значение 2 упаковывается в Promise и отправляется дальше. Вот почему мы можем позвонить .then в Зоне 3.

Что, если мы вернем обещание в цепочке?

fetch('/article/promise-chaining/user.json')
  .then(response => response.json())
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  .then(response => response.json())
  .then(githubUser => new Promise(function(resolve, reject) {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  }))
  // triggers after 3 seconds
  .then(githubUser => alert(`Finished showing ${githubUser.name}`)); 

Если мы возвращаем Promise в .then, пока обещание не будет разрешено / отклонено, следующее then в цепочке не запускается. В отличие от возврата значения, которое сразу же запускает следующее.

Отличное чтение о цепочках можно найти здесь.

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

Promise.all(arrayOfPromises).then(function(arrayOfResults) {
  //...
})

В обещаниях мы можем вернуть только ОДИН объект. В этом случае мы не можем вернуть несколько аргументов.

Разница между обратным вызовом и обещаниями

Как объяснялось выше, обещания - это более чистый способ выполнения асинхронных задач, которые больше похожи на синхронные, а также обеспечивают механизм перехвата, которого нет в обратных вызовах. Обещания строятся на обратных вызовах. Обещания - это очень мощная абстракция, позволяющая получить более чистый и лучший функциональный код с менее подверженным ошибкам шаблоном. Я бы рекомендовал получить представление о том, как все работает, и подумать с точки зрения обещаний.

Асинхронный режим и ожидание

Я писал об этом здесь вместе с тем, как тестировать реагирующие компоненты.

Вы можете связаться с автором по адресу [email protected], потому что Жизнь происходит в случайных разговорах!