Ответы пользователя по тегу Асинхронное программирование
  • Почему реджекшн главного промиса не перехватываться блоком .catch?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    Как я понимаю, этот .catch должен перехватить реджект главного
    промиса, но эта часть в принципе не выполняется и выходит
    ошибка UnhandledPromiseRejection

    Не должен, он с ним никак не связан.
    Ответ написан
    1 комментарий
  • Как переписать промис через async/await?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Код на then ждет промис из wait, а код на await нет
    await wait(2);
    Ответ написан
  • Как можно корректно написать асинхронный метод у объекта в typescript с дженериком?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    В дополнение к Aetae - дженерик здесь тоже не нужен
    Да, парсинг JSON возвращает any (по историческим причинам) и его вот таким дженериком можно легко кастануть в любой тип. Только зачем вообще использовать TypeScript если мы вечно его затыкаем своей правотой?
    Даже если данные приходят с нашего сервера, и мы точно знаем их тип - их нужно проверять, ибо нет гарантии, что никто не ошибся на бэке, что мы не ошиблись в описании типа в который кастуем.
    Поэтому должен быть тип unknown, чтоб TypeScript требовал все проверить перед использованием:
    const ApiServiceModule = {
      get: (url: string): Promise<unknown> => fetch(url)
        .then(response => response.json())
        .catch(err => console.error(err))
    }
    Ответ написан
    Комментировать
  • Как при рекурсивном переборе древовидных объектов вызывать fetch на каждый item и на выходе получать измененный массив?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    const addingOptions = arr => Promise.all(arr.map(
        item => Promise.all([
            fetchOptions(item.id),
            item.children.length ? addingOptions(item.children) : []
        ]).then(([options, children]) => ({
            ...item,
            options,
            children
        }))
    ));
    Ответ написан
    Комментировать
  • Как асинхронная программа(event loop) понимает, что пришел ответ от сервера?

    bingo347
    @bingo347
    Crazy on performance...
    Что-бы понять асинхронность полностью придется постепенно опустится на самый низкий уровень, вплоть до железа. Но начать стоит с самого верха - с уровня нашего приложения.

    Итак, мы пишем на нашем высокоуровневом любимом языке, неважно JS/Rust/C#/Scala/Python или любой другой. В современном мире у нас скорее всего есть какая либо абстракция для работы с асинхронными апи, предоставляемая или стандартной библиотекой языка или сторонними библиотеками. Она может быть примитивной и основанной на колбэках или более продвинутой, вроде Future/Promise/Task или чем-то подобным. Иногда наш язык предоставляет синтаксис наподобие async/await для более простой работы с этими абстракциями, а иногда асинхронная работа может вообще быть скрыта от нас в рантайме языка, например как с горутинами в Go. Но в любом случае где-то под капотом у нас будет event-loop, а иногда и не один, так как никто не запрещает нам писать многопоточку в то же время используя асинхронные вызовы.

    Сам event-loop - это не более чем обычный while(true) или любой другой бесконечный цикл. И внутри этого цикла наша программа имеет доступ на извлечение к некоторой очереди (если не знаете, что это за структура данных, то погуглите), которая содержит в себе результаты уже обработанных задач. Программа берет очередной результат, находит ожидающий ее колбэк/Promise/Future/Task и запускает выполнение ожидающего кода. Очередей опять же может быть несколько и обрабатываться они могут по разному, но это не важно. Важно то, что наш основной поток (или потоки) ничего не знают, о том как выполняются асинхронные задачи. Он лишь смотрит, есть ли в очереди результат, и если есть - обрабатывает его, а если нет, то принимает решение или выйти из цикла (и завершить поток, а иногда и весь процесс) или уснуть пока новых результатов не появится.

    Но откуда же в очереди берутся результаты? Надо понимать, что асинхронная программа почти всегда многопоточная и результат операций попадает в очередь из фоновых потоков, которые просто блокируются в ожидании нужного ресурса (или сразу многих ресурсов, если используют системные апи вроде epoll или kqueue). Как правило такие фоновые потоки большую часть времени находятся в состоянии ожидания, а значит не потребляют ресурсы CPU и не попадают в планировщик ОС. Такая простая модель действительно позволяет сильно экономить ресурсы по сравнению с моделью, где множество потоков выполняют по 1 задаче и самостоятельно ожидают свои запросы.

    Важно отметить, что в современном мире даже на среднеуровневых языках, вроде C или C++, не говоря уже о высокоуровневых, не реализуют асинхронность сами. Во-первых, на разных ОС для этого используются разные апи. Во-вторых, эти апи на разных ОС умеют обрабатывать разные типы ресурсов (с сетью вроде как умеют работать все основные ОС, но помимо сети асинхронно можно работать с пользовательским вводом, диском и периферийными устройствами, вроде сканеров, вебкамер и прочего цепляемого в usb). Наибольшую популярность (ИМХО) имеет кроссплатформенная библиотека libuv, хотя в Rust принято использовать mio (или даже абстракции над ней, вроде tokio), в C# подобные механизмы есть в .NET Core, а в Go оно уже зашито
    в те самые 1.5МБ рантайма, что Go засовывает в каждый бинарь
    (там правда еще и GC, но один фик это много и достойно вынесения в динамическую либу)


    Ок. С прикладным кодом вроде разобрались. А что же происходит в ядре ОС? Ведь, как писалось выше, у нас даже есть апи, чтоб ждать запросы пачкой. Все просто. Ядра ОС стали асинхронными еще до того, как это стало мейнстримом, если мы конечно имеем дело не с ОС реального времени (но у нас же винда/линь/мак/фряха, а не ОС для бортового компа боинга, где это критично). Смотрите, когда что-то происходит на внешней периферии (ну например диск запрошенные данные прочитал или по сети данные пришли, или юзер мышкой дернул), то формируется прерывание. CPU реально прерывает свою текущую работу и бежит смотреть что случилось, точнее вызывает обработчик предоставленный ОС. Но у ОС то есть основная работа, поэтому она скорее старается освободить обработчик и просто скидывает все данные в оперативку, а разбираться будет потом, когда очередь дойдет. Ничего не напоминает? Очень похоже, на то что происходило в event-loop, только вместо фоновых потоков "результаты" попадают в очередь из прерываний. А уже когда-то потом ОС отдаст данные в драйвер устройства, ну и т.д., пока они не дойдут до нашего прикладного приложения. Вот и все, никакой магии.
    Ответ написан
    3 комментария
  • Как написать асинхронную рекурсивную функцию?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    function recursiveRequest(requestData) {
      return fetch(
        //здесь формируем запрос из requestData
      ).then(response => response.json()).then(result => {
        if(result.isFinal) return result; // тут условие
        return recursiveRequest(result.nextRequest); //вызываем следующий запрос
      });
    }
    
    recursiveRequest({}).then(finalResult => {
      //работаем с последним результатом
    });
    Ответ написан
    Комментировать
  • Как правильно писать код под node js?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    new Promise((resolve, reject) => {
      fs.readFile("config.json", (err, data) => {
        if(err) {
          return reject(err);
        }
        resolve(JSON.Parse(data));
      });
    }).then(obj => {
      console.log(obj);
      // your code
    }).catch(console.error);
    Ответ написан
    3 комментария
  • Node.js что мне нужно, синхронность или асинхронность?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    node v7.6+ или транспайлим бабелем async2generators
    function requestAsync(params) {
      return new Promise((resolve, reject) => {
        request(params, (err, response, body) => {
          if(err) { return reject(err); }
          resolve({response, body});
        });
      });
    }
    
    async function getURL(_url) {
      var data, url = _url;
      do {
        const {body} = await requestAsync({url});
        data = JSON.parse(body);
        url = _url + '&pageToken=' + data.nextPageToken;
      } while(data.nextPageToken !== undefined);
      return data;
    }
    Ответ написан
    5 комментариев
  • Асинхронный цикл JavaScript & Генераторы?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Если в основе фреймворка под генераторами лежат промисы, то есть идет имитация async/await, то должно помочь так:
    * tasks() {
        let tasks = yield Task.findBy('status', 1)
    
        let promises = []
        for(let task of tasks) {
          promises.push(this.task(task))
        }
        yield Promise.all(promises)
      }
    Ответ написан
    4 комментария
  • Как сделать async/await вывод в файл в правильном порядке?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    async function saveData(data) {
      for(let id of Object.keys(data)) {
        await  appendFile(fileName, id);
        await  appendFile(fileName, data[id]);
      }
    }
    
    saveData({cat:1,dog:2})


    Как вариант, для последовательного выполнения, решить задачу чисто на промисах:
    let data = {cat:1,dog:2};
    Object.keys(data).reduce(
      (p, id) => p
        .then(() => appendFile(fileName, id))
        .then(() => appendFile(fileName, data[id])),
      Promise.resolve()
    );
    Ответ написан
  • Как загрузить коллекцию объектов по средствам ajax запроса в цикле foreach?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    промисы в помощь
    this.getDataForPlaces = function(addresses){
       return Promise.all(Array.prototype.map.call(addresses, function(address) {
          return getLocationDesc(address);
       }));
    };
    
    function getLocationDesc(address) {
       return new Promise(function(resolve, reject) {
          var parameters = [];
                
                var message = {
                    'action' : 'http://api.yelp.com/v2/search',
                    'method' : 'GET',
                    'parameters' : parameters
                };
    
                OAuth.setTimestampAndNonce(message);
                OAuth.SignatureMethod.sign(message, accessor);
    
                var parameterMap = OAuth.getParameterMap(message.parameters);
                $.ajax({
                    url : message.action,
                    cache : true,
                    method : message.method,
                    data : parameterMap,
                    dataType : 'jsonp',
                    jsonp : 'callback',
                    success : resolve,
                    error : reject
                });
       });
    };


    Только что-то мне подсказывает, что у Вас в getLocationDesc ошибка, аргумент address никак не используется
    Ответ написан
    2 комментария
  • Можно ли упростить асинхронный код на Promise?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Вынесите someObject в замыкание и внутреннюю цепочку промисов перенесите во внешнюю
    someObject = null //не знаю можно ли писать в cs var поэтому так
    Promise.resolve()
    .then(@getObjectDescription.bind(@))
    .then(
      (so) ->
        someObject = so
    )
    .then(@getSomeSpecialFieldValue.bind(@))
    .then(
            (value) ->
              someObject.special_field = value
              return someObject
    )
    .then(
      (someObject) ->
        data = new FormData()
    
        data.append('field', someObject.field)
        data.append('special_field', someObject.special_field)
    
        options =
          method: 'post'
          body: data
    
        return options
    )
    .then(@execute.bind(@, 'rest.api.method'))
    Ответ написан
    1 комментарий