Как JavaScript обещает работать за кулисами - PullRequest
2 голосов
/ 26 апреля 2020

Я так растерялся из-за того, что происходит за кулисами, когда обещание производится и потребляется. Прошу прояснить мои моменты и извините за мой слабый Engli sh.

  1. создается пустой объект с новым ключевым словом. Вызывается конструктор Promise, а новое ключевое слово устанавливает конструктор this of Promise, указывая на пустой объект this = blankobject.
  2. Конструктор Promise получает обратный вызов (функция executor) в аргументе и вызывает функцию executor.
  3. Функция executor получает два обратных вызова (resolve, reject) в качестве аргументов
  4. setTimeout получает вызывается в функции executor, и setTimeOut имеет асин c код
  5. асин c код переходит в фон, а затем конструктор Promise возвращает объект Promise, ранее пустой объект, и ссылку на объект Promise, сохраненную в myPromise.
  6. переменная создана

Что будет дальше? Когда вызывается метод then, код метода then переходит в фоновый режим? Я предполагаю, что он переходит в фоновый режим, а переменная - console.log // 10

После завершения выполнения основного кода асин c запуск кода setTimeout обратный вызов начинает выполняться, а после завершения выполнения обещание выполняется и разрешается. функция возвращает значение. Как это значение хранится в объекте обещания и что происходит в методе then?

let myPromise = new Promise (
    (resolve, reject) => {

        setTimeout(() => {
            console.log(getIDs)
            resolve(10);

        }, 1500);

    }
)


let a = 10
        myPromise.then(val => {
            console.log(val);

        })
        console.log(a)

Ответы [ 2 ]

3 голосов
/ 27 апреля 2020

Ниже приведена упрощенная реализация встроенного класса Promise . catch и finally не были реализованы.

Функция, предоставленная конструктору Promise, называется функцией executor и вызывается немедленно и синхронно.

Каждое обещание имеет метод .then, позволяющий объединять в цепочку обещания.

Функции, переданные в .then , всегда вызываются асинхронно в микрозадаче (обратите внимание на использование queueMicrotask ниже).

Каждый раз, когда вызывается .then, создается и возвращается новое обещание.

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

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

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

function Promise(executor) {
  if (!executor) throw "Promise executor undefined"
  let status = "pending", value, thenQ = []

  const then = onFulfilled => {
    let resolver
    // This ensures control does not move to later promises 
    // until prior promises have been resolved.
    const nextPromise = new Promise(resolve => (resolver = resolve))
    // More than one "then" can be registered with each promise.
    thenQ.push((...args) => resolver(onFulfilled(...args)))
    return nextPromise
  }

  // We check if the result is a "thenable"; if so, we treat
  // it as an inner promise, otherwise we simply fulfil with 
  // the result.
  const resolve = result => result?.then ? result.then(fulfil) : fulfil(result)

  // When a promise has been fulfilled, its "thens" can be run.
  const fulfil = result => (status = "fulfilled", value = result, executeThens(value))

  // "Thens" are run asynchronously, on a microtask.
  const executeThens = value => queueMicrotask(() => thenQ.forEach(el => el(value)))

  // The executor is run synchronously.
  executor(resolve)

  return {
    then,
    get status() { return status },
    get value() { return value }
  }
}

// Chaining
new Promise(resolve => {
  console.log('Waiting for step 1...')
  setTimeout(() => resolve("One, two..."), 1500)
})
.then(result => new Promise(resolve => {
  console.log('Waiting for step 2...')
  setTimeout(() => resolve(`${result}three, four`), 1500)
}))
.then(result => console.log(`Chaining result: ${result}.`))

// Branching
const p = new Promise(resolve => {
  console.log('Waiting for step a...')
  setTimeout(() => resolve("Alpha, Bravo..."), 1500)
})

p.then(result => new Promise(resolve => {
  console.log('Waiting for step b1...')
  setTimeout(() => resolve(`${result}Charlie, Delta`), 1500)
})).then(console.log)

p.then(result => {
  console.log('Waiting for step b2...')
  return `${result}Echo, Foxtrot`
}).then(console.log)

См. также .

1 голос
/ 26 апреля 2020

Я буду go через ваш код в порядке выполнения.

Всегда this всегда равно значению, которое было в начале. Это потому, что вы используете только функции стрелок. Но это не имеет значения, поскольку вы не ссылаетесь на this.

Основной код

let myPromise = new Promise(executor); создает объект ожидающего обещания. При создании обещания будет выполняться функция executor.

setTimeout(callback, 1500); помещает функцию callback в некоторую внутреннюю очередь таймера. Механизм javascript обещает приложить все усилия, чтобы выполнить callback после (как минимум) 1500 мс.

let a = 10; устанавливает переменную a в 10.

myPromise.then(onFulfilled); создает еще одно ожидающее обещание. Он связан с myPromise, так что onFulfilled будет планироваться асинхронно при выполнении myPromise.

console.log(a); печатает значение a, равное 10.

В течение следующих 1500 мс ничего не происходит. Затем выполняется callback.

обратный вызов setTimeout

console.log(getIDs); печатает getIDs. По названию можно догадаться, что это функция. Таким образом, будет напечатано что-то вроде [Function: getIDs].

resolve(10); выполняет myPromise и устанавливает его результат равным 10. Поскольку myPromised теперь выполняется, onFulfilled из anotherPromise назначается асинхронно.

Теперь нам нужно дождаться обработки стека вызовов. После этого будет вызван onFulfilled.

onFulfilled of myPromise.then

console.log(val); печатает содержимое val. То есть результат myPromise.

...