Популярные задачки
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
console.log(1)выполняется первым, так как управление происходит синхронно.console.log(2)выполняется следующим в рамках определенияPromise.- Выполняется
resolve(), но обработкаPromise (.then())происходит в очереди микрозадач, которая выполняется после завершения текущей задачи. console.log(3)выполняется дальше, поскольку он все еще является частью определенияPromise, которое выполняется синхронно.console.log(4)выполняется в рамках основного управления.- Далее выполняется
console.log(7). - После завершения основного потока управления следующий элемент в очереди микрозадач выбирается. Здесь выполняется
console.log(5). Строка с.then()создает еще один промис, который снова попадает в очередь микрозадач. - Затем обрабатывается вторая микрозадача, выводится
console.log(6). - Когда все микрозадачи завершены, мы имеем дело с
setTimeoutс задержкой 0. Но несмотря на то, что время равно 0, это все равно помещает обратный вызов в очередь макрозадач, которая обрабатывается только после выполнения всех микрозадач. Итак, выводитсяconsole.log(9). - В конце концов,
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
Promise.resolve(1)создает выполненный промис со значением 1. Следующий обработчикthen()получит это значение.then(() => 2)не обращает внимания на переданное значение 1 и возвращает 2. Это 2 не становится цепочкой промисов, но становится выполненным значением для следующего обработчикаthen().then(3)- это несколько иной случай.then()ожидает функцию в качестве аргумента. Здесь 3 не является функцией, поэтому данный обработчикthen()фактически ничего не делает. Он просто передает предыдущее выполненное значение, которое равно 2.then((value) => value * 3)принимает значение 2, переданное из предыдущегоthen(), умножает его на 3, получая 6, и передает это 6 следующему обработчикуthen().then(Promise.resolve(4))подобноthen(3), это еще один случай, когдаthen()получает нефункциональный аргумент (на этот раз это выполненный промис, а не прямое значение, как 3). Таким образом, он также ничего не делает и просто передает предыдущее выполненное значение 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
let a = 1объявляет и инициализирует a значением 1.const b = ++aувеличиваетaна 1 до присвоения значенияb. Так что сейчасa = 2иb = 2.const c = a++присваивает текущее значениеaпеременнойc, а затем увеличиваетaна1. Следовательно,c = 2, аa = 3.- Финальные значения, выводимые в выражениях
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() вочередь создает новый промис, который решается на основании выполнения предыдущего обработчика. Если обработчик возвращает значение, которое не является промисом, этим значением выполняется следующий промис. Если обработчик возвращает промис, следующий промис будет выполнен с результатом этого промиса.
Объясним ваш пример шаг за шагом:
Promise.resolve(1): Создается промис, который немедленно решается с значением1..then((val) => { console.log(val); return val + 1 }): Обработчик берет значение1, выводит его в консоль, затем возвращает2. Поскольку это не промис, следующий промис решается с значением2..then((val) => { console.log(val) }): Этот обработчик получает значение 2, выводит его в консоль, затем не возвращает ничего. По умолчанию, если функция не возвращает значение, она возвращаетundefined, поэтому следующий промис решается со значениемundefined..then((val) => { console.log(val); return Promise.resolve(3).then((val) => { console.log(val) }) }): Этот обработчик получаетundefined, выводит его в консоль, затем создает новый промис, который решается со значением3. Этот новый промис затем печатает3в консоль и не возвращает ничего, так что фактически он решается со значениемundefined..then((val) => { console.log(val); return Promise.reject(4) }): Этот обработчик получает undefined, выводит его в консоль, затем возвращает новый промис, который немедленно отклоняется со значением4..catch((val) => { console.log(val) }): Обработчик ошибок перехватывает отклоненный промис со значением4, затем выводит его в консоль и по умолчанию возвращаетundefined..finally((val) => { console.log(val); return 10 }): Несмотря на название, методfinallyна самом деле не получает никакого значения. Вместо этого он выполняется, независимо от того, был ли предыдущий промис выполнен успешно или отклонен. Вывод в консоль будетundefined, возвращаемое значение10будет проигнорировано..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'.