Несколько вопросов о Promise в JavaScript - PullRequest
0 голосов
/ 25 декабря 2018

Меня смущает поведение Promise в JavaScript, и у меня есть вопросы, может кто-нибудь помочь мне разобраться в них?

  1. Это два распространенных способа создания Promise.

    function promise(){
        return new Promise((resolve, reject) => {
            resolve()});
    }
    
    let promise = new Promise(function(resolve, reject){
        resolve();
    });
    

    Первая функция создает объект Promise, но не вызывает его, пока мы не вызовем функцию.Для сравнения, второй оператор создает объект Promise и вызывает его немедленно.Я прав?

  2. Для этой функции:

    function timeout(ms){
        return new Promise((resolve, reject) => {
            setTimeout(resolve, ms, 'done');
    });
    }
    
    timeout(100).then((value) => {
        console.log(value);
    });
    

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

  3. Эти два оператора равны?

    let promise = new Promise(function(resolve, reject){
        resolve();
    });
    
    let promise = Promise.resolve();
    
  4. Почему выводпоследовательность, подобная следующей?

    setTimeout(function(){
        console.log('3');
    }, 0);
    
    Promise.resolve().then(function(){
        console.log('2');
    });
    
    console.log('1');
    
    // 1
    // 2
    // 3
    

    Это пример из книги, автор объясняет следующим образом: setTimeout(fn, 0) будет вызываться в начале следующего цикла обработки событий, Promise.resolve() будетвызывается в конце текущего цикла событий, и console.log() будет вызван немедленно.

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

Ответы [ 3 ]

0 голосов
/ 25 декабря 2018
  1. Нет, функция не будет создавать обещание, пока вы его не вызовете.
  2. Обещание будет создано, когда вы вызовете timeout (100), и будет решено в setTimeout.Не уверен насчет деталей с очередью событий.
  3. Кажется так (пробовал в консоли).
  4. Конечно, посмотрите это Филип Робертс: Какого черта цикл событий в любом случае?|JSConf EU минута 11:30 или около того.
0 голосов
/ 25 декабря 2018

Первая функция создает объект Promise, но не вызывает его, пока мы не вызовем функцию.Для сравнения, второй оператор создает объект Promise и вызывает его немедленно.Я прав?

Первая функция - это просто функция.Пока это не называется, обещание не создается.Как только он вызван, нет особой разницы с прямым исполнением, которое вы указали в качестве альтернативы.

Я думаю, что когда мы вызываем функцию тайм-аута, она сначала создает асинхронную функцию setTimeout * 1008.*

setTimeout не создан, функция существует как встроенная функция.Вы можете сказать, что это называется .

... и толкает его в конец очереди событий.

Не сама функция setTimeout помещается в очередь.Это обратный вызов (resolve в данном случае), включая аргументы, период ожидания и уникальный идентификатор таймера, который заносится в список активных таймеров.

После завершения всех синхронных событий он будетвызывается и создает объект Promise.

Объект Promise создается во время вызова функции timeout.

Обратный вызов, который передается на new Promise, обычно называется обратным вызовом конструктора обещаний , именно в момент выполнения new Promise выполняется также этот обратный вызов (синхронно) иобещание создано.

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

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

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

Так что, похоже, есть два цикла событий, я прав?

Как минимум два;может быть больше.Например, в контексте браузера может быть еще одна очередь для событий, касающихся мутации элемента DOM.См. Также этот ответ о том, что об этом говорят различные спецификации.

Являются ли эти два утверждения равными?

Практически да;Promise.resolve() - это сокращение от new Promise(r => r())

Почему выходная последовательность похожа на следующую?

setTimeout включает очередь задач, тогда как .then включаеточередь микрозадач, которая всегда используется перед обработкой очереди задач;по крайней мере, это консенсус в текущих реализациях.

Приложение

Вот некоторые пояснения к последовательности событий следующего кода:

function timeout(ms){
    return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done');
    });
}

timeout(100).then((value) => {
    console.log(value);
});

Сначала кодпроанализировали и создали задачу для ее выполнения:

Задача 1

  • Определяется функция timeout (переменная поднятая с функцией в качестве значения)
  • timeout вызывается с аргументом 100
  • Объект обещания создается, и обратный вызов конструктора вызывается синхронно.Два аргумента предоставляются системой.Они являются внутренними функциями, которые мы можем вызывать, когда обещание должно перейти в выполненное или отклоненное состояние (это мы должны решить).
  • setTimeout вызывается.
  • Аргументы, переданные в setTimeout, используются для создания записи во внутреннем списке таймеров.
  • Идентификатор таймера возвращается, но ваш код не использует возвращаемое значение.
  • Созданный объект обещания возвращается вызывающей стороне timeout
  • Вызывающий объект вызывает метод then этого обещания, передавая ему какую-либо функцию (функцию с console.log)
  • Внутренняя реализация обещания сохраняет эту функцию в очереди (не очереди событий)для возможного последующего выполнения
  • Достигнут конец кода, стек вызовов пуст
  • Очередь микро-задач проверяется на наличие любых записей, но она также пуста

В фоновом режиме:

  • Время таймера истекает, и запись помещается в очередь задач.Это ожидающий вызов функции, которая была передана в setTimeout, т.е. в нашем случае resolve.Как именно это происходит, зависит от реализации.Суть в том, что в какой-то момент очередь задач имеет эту задачу, которую можно использовать.

Задача 2

  • Запись в очереди задач (для вызова resolve) найдена и обработана
  • resolve называется
  • Внутренние объекты обещания (в которых реализована эта resolve функция) помечают обещание как разрешенное
  • Внутренние элементы обещания создают записи в очереди микрозаданий: по одной для каждого обратного вызова then (или await)он сохранил в своей внутренней очереди.В этом случае есть только одна такая запись: анонимная функция, которая была передана единственному методу then в коде.
  • Стек вызовов пуст (это был только вызов resolve)
  • Микро-очередь задач проверяется на наличие любых записей, и есть одна:

Задача 2, Микро-задача 1

  • Одна запись в микро-задачеочередь задач потребляется
  • анонимная функция называется
  • console.log выполняется
  • Реализация console выдает вывод
  • стек вызовов пуст
  • Нет больше записей в очереди микро задач

Больше нет записей в очереди задач.Система продолжает проверять наличие новых записей в очереди задач.

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

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

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