Популярные задачки

1 Promise order (opens in a new tab)

console.log(1)
const promise = new Promise((resolve) => {
  console.log(2)
  resolve()
  console.log(3)
})
 
console.log(4)
 
promise.then(() => {
  console.log(5)
}).then(() => {
  console.log(6)
})
 
console.log(7)
 
setTimeout(() => {
  console.log(8)
}, 10)
 
setTimeout(() => {
  console.log(9)
}, 0)

Ответ: 1, 2, 3, 4, 7, 5, 6, 9, 8

  1. console.log(1) выполняется первым, так как управление происходит синхронно.
  2. console.log(2) выполняется следующим в рамках определения Promise.
  3. Выполняется resolve(), но обработка Promise (.then()) происходит в очереди микрозадач, которая выполняется после завершения текущей задачи.
  4. console.log(3) выполняется дальше, поскольку он все еще является частью определения Promise, которое выполняется синхронно.
  5. console.log(4) выполняется в рамках основного управления.
  6. Далее выполняется console.log(7).
  7. После завершения основного потока управления следующий элемент в очереди микрозадач выбирается. Здесь выполняется console.log(5). Строка с .then() создает еще один промис, который снова попадает в очередь микрозадач.
  8. Затем обрабатывается вторая микрозадача, выводится console.log(6).
  9. Когда все микрозадачи завершены, мы имеем дело с setTimeout с задержкой 0. Но несмотря на то, что время равно 0, это все равно помещает обратный вызов в очередь макрозадач, которая обрабатывается только после выполнения всех микрозадач. Итак, выводится console.log(9).
  10. В конце концов, setTimeout с задержкой 10 мс будет последним, так как он отправляется в API и ожидает 10 мс, прежде чем его поместят в очередь макрозадач. В итоге выводится console.log(8).

2 promise executor (opens in a new tab)

new Promise((resolve, reject) => {
  resolve(1)
  resolve(2)
  reject('error')
}).then((value) => {
  console.log(value)
}, (error) => {
  console.log('error')
})

Ответ: 1

Потому что Promise может изменить свое состояние лишь один раз, поэтому отработает любой первый вызов, что и будет результатом

3 Promise then callbacks (opens in a new tab)

Promise.resolve(1)
.then(() => 2)
.then(3)
.then((value) => value * 3)
.then(Promise.resolve(4))
.then(console.log)

Ответ: 6

  1. Promise.resolve(1) создает выполненный промис со значением 1. Следующий обработчик then() получит это значение.
  2. then(() => 2) не обращает внимания на переданное значение 1 и возвращает 2. Это 2 не становится цепочкой промисов, но становится выполненным значением для следующего обработчика then().
  3. then(3) - это несколько иной случай. then() ожидает функцию в качестве аргумента. Здесь 3 не является функцией, поэтому данный обработчик then() фактически ничего не делает. Он просто передает предыдущее выполненное значение, которое равно 2.
  4. then((value) => value * 3) принимает значение 2, переданное из предыдущего then(), умножает его на 3, получая 6, и передает это 6 следующему обработчику then().
  5. then(Promise.resolve(4)) подобно then(3), это еще один случай, когда then() получает нефункциональный аргумент (на этот раз это выполненный промис, а не прямое значение, как 3). Таким образом, он также ничего не делает и просто передает предыдущее выполненное значение 6.
  6. Наконец, then(console.log) записывает переданное значение, которое равно 6.

Block scope 1 (opens in a new tab)

for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 0)
}
 
for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 0)
}

Ответ: 5555501234

Increment operator (opens in a new tab)

let a = 1
const b = ++a
const c = a++
console.log(a)
console.log(b)
console.log(c)

Ответ: 322

  1. let a = 1 объявляет и инициализирует a значением 1.
  2. const b = ++a увеличивает a на 1 до присвоения значения b. Так что сейчас a = 2 и b = 2.
  3. const c = a++ присваивает текущее значение a переменной c, а затем увеличивает a на 1. Следовательно, c = 2, а a = 3.
  4. Финальные значения, выводимые в выражениях console.log, — это a = 3, b = 2 и c = 2. В JavaScript ++a (оператор преинкремента) увеличивает значение a до оценки окружающего выражения, в то время как a++ (оператор постинкремента) увеличивает значение a после его оценки.

4 Promise then callbacks II (opens in a new tab)

Promise.resolve(1)
.then((val) => {
  console.log(val)
  return val + 1
}).then((val) => {
  console.log(val)
}).then((val) => {
  console.log(val)
  return Promise.resolve(3)
    .then((val) => {
      console.log(val)
    })
}).then((val) => {
  console.log(val)
  return Promise.reject(4)
}).catch((val) => {
  console.log(val)
}).finally((val) => {
  console.log(val)
  return 10
}).then((val) => {
  console.log(val)
})

Ответ: 1 2 undefined 3 undefined 4 undefined undefined

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

  1. Promise.resolve(1): Создается промис, который немедленно решается с значением 1.
  2. .then((val) => { console.log(val); return val + 1 }): Обработчик берет значение 1, выводит его в консоль, затем возвращает 2. Поскольку это не промис, следующий промис решается с значением 2.
  3. .then((val) => { console.log(val) }): Этот обработчик получает значение 2, выводит его в консоль, затем не возвращает ничего. По умолчанию, если функция не возвращает значение, она возвращает undefined, поэтому следующий промис решается со значением undefined.
  4. .then((val) => { console.log(val); return Promise.resolve(3).then((val) => { console.log(val) }) }): Этот обработчик получает undefined, выводит его в консоль, затем создает новый промис, который решается со значением 3. Этот новый промис затем печатает 3 в консоль и не возвращает ничего, так что фактически он решается со значением undefined.
  5. .then((val) => { console.log(val); return Promise.reject(4) }): Этот обработчик получает undefined, выводит его в консоль, затем возвращает новый промис, который немедленно отклоняется со значением 4.
  6. .catch((val) => { console.log(val) }): Обработчик ошибок перехватывает отклоненный промис со значением 4, затем выводит его в консоль и по умолчанию возвращает undefined.
  7. .finally((val) => { console.log(val); return 10 }): Несмотря на название, метод finally на самом деле не получает никакого значения. Вместо этого он выполняется, независимо от того, был ли предыдущий промис выполнен успешно или отклонен. Вывод в консоль будет undefined, возвращаемое значение 10 будет проигнорировано.
  8. .then((val) => { console.log(val) }): Обработчик принимает undefined (поскольку finally не изменяет полученное ранее значение).

6 Arrow Function (opens in a new tab)

const obj = {
  dev: 'bfe',
  a: function() {
    return this.dev
  },
  b() {
    return this.dev
  },
  c: () => {
    return this.dev
  },
  d: function() {
    return (() => {
      return this.dev
    })()
  },
  e: function() {
    return this.b()
  },
  f: function() {
    return this.b
  },
  g: function() {
    return this.c()
  },
  h: function() {
    return this.c
  },
  i: function() {
    return () => {
      return this.dev
    }
  }
}
 
console.log(obj.a())
console.log(obj.b())
console.log(obj.c())
console.log(obj.d())
console.log(obj.e())
console.log(obj.f()())
console.log(obj.g())
console.log(obj.h()())
console.log(obj.i()())

Ответ: bfe, bfe, undefined, bfe, bfe, undefined, undefined, undefined, bfe

  • obj.a(): this внутри метода a ссылается на obj. Значение this.dev будет 'bfe'.
  • obj.b(): this внутри метода b (как и в a()) ссылается на obj. Значение this.dev будет 'bfe'.
  • obj.c(): this внутри стрелочной функции указывает на контекст, в котором функция была объявлена. В глобальном контексте this.dev не определено, поэтому результат будет undefined.
  • obj.d(): this внутри возвращаемой стрелочной функции будет ссылаться на этот же контекст, что и this внутри функции d, то есть на obj. Поэтому this.dev вернет 'bfe'.
  • obj.e(): this.b() вызывается в контексте obj, поэтому this.dev внутри b будет 'bfe'.
  • obj.f()(): this.b внутри f возвращает ссылку на функцию b, но контекст this функции obj.f потерян при вызове: результат выполнения obj.f() вызывается как функция с обычной нотацией вызова функции, а не как метод. Из-за этого this внутри b, когда он вызывается, не ссылается на obj, а ссылается на глобальный контекст, в котором dev не определён. Поэтому результат будет undefined.
  • obj.g(): this.c() вызывается внутри g, где this указывает на obj. Однако, внутри c, this снова указывает на глобальный контекст, так как c объявлена как стрелочная функция. this.dev в глобальном контексте не определено, поэтому результат будет undefined.
  • obj.h()(): this.c возвращает ссылку на функцию c, и this потерян также, как и в obj.f()(). Поэтому this внутри c, когда он вызывается, не ссылается на obj, а ссылается на глобальный контекст. Поэтому будет возвращено undefined.
  • obj.i()(): this внутри функции i ссылается на obj, а this внутри возвращаемой стрелочной функции будет указывать на этот же контекст, что и this внутри i, то есть на obj. Поэтому this.dev внутри возвращаемой функции будет 'bfe'.