Рубрики
Без рубрики

Как сделать обещание из функции обратного вызова в JavaScript

Adham El Banhawy Как сделать обещание из функции обратного вызова в JavaScriptback-End Developers вступит в вызовы во время создания приложений или тестирования кода. Как разработчик, который довольно новое и знакомится с этими проблемами, я никогда не столкнулся с проблемой или

Автор оригинала: FreeCodeCamp Community Member.

Adham El Banhawy

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

Я не собираюсь углубиться слишком глубоко в деталях обратного вызова и его плюсов и минусов или альтернатив, таких как обещания и Async/ждут. Для более яркого объяснения вы можете проверить Эта статья что объясняет их тщательно.

Обратный ад

Обратные вызовы – это полезная особенность JavaScript, которая позволяет сделать асинхронные вызовы. Они являются функциями, которые обычно передаются в качестве второго параметра на другую функцию, которая получает данные или выполнение операции ввода/вывода, которая требует времени для завершения.

Например, попробуйте сделать вызов API, используя Запрос Модуль или подключение к базе данных MongoDB. Но что, если оба звонков зависят друг от друга? Что если данные, которые вы получаете, это URL MongoDB, к которому вам нужно подключиться к?

Вам придется гнездить эти звонки внутри друг друга:

request.get(url, function(error, response, mongoUrl) {

  if(error) throw new Error("Error while fetching fetching data");
  
  MongoClient.connect(mongoUrl, function(error, client) {
  
    if(error) throw new Error("MongoDB connection error");
    
    console.log("Connected successfully to server");    
    const db = client.db("dbName");
    // Do some application logic
    client.close();
    
  });
  
});

Хорошо … Так где проблема? Ну, за одну вещь читаемость кода страдает от этой техники.

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

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

Я слышу некоторые из вас, в том числе мои наилучшие себя, говоря мне обернуть его в async Функция тогда ждать Функция обратного вызова. Это просто не работает.

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

Вот эта ошибка, которую я сделал раньше:

var request = require('request');

// WRONG

async function(){
    
  let joke;
  let url = "https://api.chucknorris.io/jokes/random"
  
  await request.get(url, function(error, response, data) {
      
    if(error) throw new Error("Error while fetching fetching data");
      
    let content = JSON.parse(data);
    joke = content.value;
      
  });
    
  console.log(joke); // undefined
    
};

// Wrong

async function(){
    
  let joke;
  let url = "https://api.chucknorris.io/jokes/random"
  
  request.get(url, await function(error, response, data) {
      
    if(error) throw new Error("Error while fetching fetching data");
      
    let content = JSON.parse(data);
    joke = content.value;
      
  });
    
  console.log(joke); // undefined
    
};

Некоторые более опытные Devs могут сказать: «Просто используйте другую библиотеку, которая использует обещания, чтобы сделать то же самое, например Axios , или просто использовать Fetch » Отказ Конечно, я могу в этом сценарии, но это просто убегает от проблемы.

Кроме того, это просто пример. Иногда вы можете быть заблокированы в использовании библиотеки, которая не поддерживает обещания без альтернатив. Как и использовать комплекты разработки программного обеспечения (SDK) для связи с платформами, такими как Amazon Web Services (AWS), Twitter или Facebook.

Иногда даже используя обратный вызов, чтобы сделать очень простой вызов с помощью быстрой операции ввода-вывода или CRUD, и другая логика зависит от его результатов. Но вы можете быть ограничены средой выполнения, как в Лямбда Функция Что убьет весь процесс после окончания основных потоков, независимо от любых асинхронных вызовов, которые не были завершены.

Решение 1 (легко): используйте модуль узла “UTIL”

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

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

const request = require('request');

const util = require('util');

const url = "https://api.chucknorris.io/jokes/random";

// Use the util to promisify the request method

const getChuckNorrisFact = util.promisify(request);

// Use the new method to call the API in a modern then/catch pattern

getChuckNorrisFact(url).then(data => {

   let content = JSON.parse(data.body);
   
   console.log('Joke: ', content.value);
   
}).catch(err => console.log('error: ', err))

Приведенный выше код решает проблему аккуратно используя Util.promisify Метод доступен из Nodejs Core Bibly.

Все, что вам нужно сделать, это использовать функцию обратного вызова в качестве аргумента для UTIL.PROMISIFY и хранить ее переменной. В моем случае это getchucknorrisfact Отказ Затем вы используете эту переменную в качестве функции, которую вы можете использовать как обещание с .then () и .catch () методы.

Решение 2 (вовлечено): превратить обратный вызов в обещание

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

Давайте возьмем пример Чука Норриса выше и превратимся в обещание.

var request = require('request');
let url = "https://api.chucknorris.io/jokes/random";

// A function that returns a promise to resolve into the data //fetched from the API or an error
let getChuckNorrisFact = (url) => {
  return new Promise(
    (resolve, reject) => {
      request.get(url, function(error, response, data){
        if (error) reject(error);
          
let content = JSON.parse(data);
        let fact = content.value;
        resolve(fact);
      })
   }
 );
};

getChuckNorrisFact(url).then(
   fact => console.log(fact) // actually outputs a string
).catch(
   error => console.(error)
);

В указанном выше коде я положил обратный вызов Запрос Функция внутри обертки обещания Обещание (((разрешение, отклонение) => {//Функция обратного вызова}) Отказ Эта обертка позволяет нам позвонить в getchucknorrisfact функция как обещание с .then () и .catch () методы. Когда getchucknorrisfact называется, он выполняет запрос на API и ждет Для либо разрешать () или Отклонить () утверждение для выполнения. В функции обратного вызова вы просто передаете полученные данные в методы разрешения или отклонения.

После того, как данные (в этом случае удивительный чек Норрис факт) выясняется и передается в Resolver, getchucknorrisfact Выполняет тогда () метод. Это вернет результат, который вы можете Используйте внутри функции внутри тогда () Чтобы сделать желаемую логику – в этом случае отображать его к консоли.

Вы можете прочитать больше об этом в MDN веб-документы.