Как написать пользовательскую асинхронную функцию в Node.js - PullRequest
0 голосов
/ 08 декабря 2018

Я новичок в JavaScript, пытаясь понять вызов асинхронной функции.Вот моя js-программа:

var notify =  function () {
    console.log('before');
    doPost('data', (res) => {
        console.log('callback received');
    });
    console.log('after');
}
var doPost = function (data) {
    console.log(data);
    while (true) {
        //do nothing
    }    
}
notify();

Если мое понимание правильное, notify () -> doPost () работает асинхронно, поэтому «после» должно быть напечатано сразу после «до».Но этого не происходит.Моя программа ждет бесконечный цикл, чтобы завершить в первую очередь.Я знаю, что в моем понимании есть какая-то лазейка.Пожалуйста, помогите.

Я попробовал эти две программы ниже: эта снова показывает поведение синхронизации.Печатает: - перед данными

 var notify = function () {
    console.log('before');
    doPost('data').then((res) => {
        console.log('callback received');
    });
    console.log('after');

}
var doPost = function (data) {
    console.log(data);
    return new Promise((resolve, reject) => {
        resolve('resolved');
        while (true) {
            //do nothing           
        }
    });
};
notify();

Однако, если я просто удалю бесконечно работающий цикл while, он начнет показывать асинхронное поведение.Печатает: - до получения данных после обратного вызова

var notify = function () {
    console.log('before');
    doPost('data').then((res) => {
        console.log('callback received');
    });
    console.log('after');

}
var doPost = function (data) {
    console.log(data);
    return new Promise((resolve, reject) => {
        resolve('resolved');
        while (false) {
            //do nothing           
        }

    });
};
notify();

Это за пределами моего понимания.Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

0 голосов
/ 08 декабря 2018

Почему вы хотите написать свои собственные асинхронные функции?Уже доступно так много разных утилит:

Посмотрите примеры здесь.Разве это не поможет?https://caolan.github.io/async/

0 голосов
/ 08 декабря 2018

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

Но что на самом деле означает синхронизация, асинхронная, параллельная, одновременная работа?

Синхронный код - самый простой в работес, потому что это дает лучшие гарантии:

/* 1 */ doWorkSync(() => console.log("callback"));
/* 2 */ console.log("after doWorkSync");

В приведенном выше коде, где doWorkSync - синхронная функция, мы знаем, что функция обратного вызова будет выполняться перед строкой 2.

Параллельный код, который вjavascript, обычно называемый async, дает нам немного худшую гарантию:

/* 1 */ doWorkAsync(() => console.log("callback"));
/* 2 */ console.log("after doWorkAsync");

В приведенном выше коде мы гарантируем, что функция обратного вызова будет вызвана после полного выполнения текущего синхронного кода, то есть после строки 2. Но мы не делаемточно знать когда.Он может быть вызван немедленно, но может быть вызван намного позже.

Но наиболее сложный код для работы - это параллельный код:

/* 1 */ doWorkParallel(() => console.log("callback"));
/* 2 */ console.log("after doWorkParallel");

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

Самый простой способ написать асинхронную (параллельную) функцию в JavaScript - это использовать Promise:

console.log("first");
Promise.resolve().then(() => console.log("last"));
console.log("second");

В приведенном выше коде then обратный вызов выполняется сразу после того, как текущий синхронный код запускается из очереди микрозадач.

Параллельный код может быть выполнен вJavaScript с Worker s:

function parallel() {

  function work() {
    block(200); // message from the main thread is logged while this blocks the worker
    console.log("second"); // logs from the worker can be seen in the browser console

    function block(time) {
      const startDate = Date.now();
      while (startDate + time > Date.now()) {};
    }
  }

  new Worker(window.URL.createObjectURL(new Blob([`(${work})()`]), {
    type: 'application/javascript'
  }));

}

function block(time) {
  const startDate = Date.now();
  while (startDate + time > Date.now()) {}
}

parallel();

// timeout is needed because blob response is handled on the main thread
setTimeout(() => { 
  console.log("first");
  block(500); //  message from parallel is logged while this blocks the main thread
  console.log("last");
}, 100)
0 голосов
/ 08 декабря 2018

Использование обратных вызовов или обещаний не обязательно означает, что что-то является асинхронным.Возьмите этот пример:

   console.log("before");
   [1, 2, 3].forEach(console.log);
   console.log("after");

Это будет регистрировать все по порядку, так как .forEach вызывает обратный вызов синхронно.Однако существуют также асинхронные обратные вызовы, например setTimeout:

 console.log("before");
 setTimeout(function later() {
   console.log("later");
  }, 0);
  console.log("after");

Здесь вы увидите «до», «после», «позже», так как функция later выполняется асинхронно , когда таймер завершен.Чтобы получить асинхронное поведение, вам нужен «асинхронный обратный вызов корня», все обратные вызовы / обещания, основанные на чем-то асинхронном, также являются асинхронными.В Javascript есть только несколько таких «асинхронных корней», а именно setTimeout и setInterval, fetch и обработчики событий DOM в браузерах или все операции ввода-вывода в nodejs.В вашем коде нет ни одного из них, поэтому он, независимо от того, что вы делаете, полностью синхронен.

Чтобы он работал асинхронно, добавьте асинхронный обратный вызов:

function notify() { // function declarations look so much better than function expressions, and they are easier to handle
  console.log('before');
  doPost('data', (res) => {
    console.log('callback received');
  });
  console.log('after');
}

function doPost(data, callback) { // you pass a callback, so you should take it here
  console.log(data);
  setTimeout(callback, 1, "result"); // call back asynchronously
}

notify();

Oh иwhile(true) обычно является показателем того, что вы сделали что-то очень неправильное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...