Принцип реализации обещания (с исходным кодом)

внешний интерфейс JavaScript Promise

Эта статья предназначена в основном для изученияPromiseПринцип реализации, приведет вас шаг за шагом к реализацииPromise, я не буду объяснять его использование.Если читатель все еще не понимает, как используется Promise, вы можете проверить Ruan YifengУчебное пособие по обещаниям ES6.

Далее, шаг за шагом, чтобы достичьPromise

1. PromiseБазовая структура

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('FULFILLED')
  }, 1000)
})

КонструкторPromiseдолжен принимать функцию в качестве аргумента, давайте вызовем эту функциюhandle,handleтакже содержитresolveиrejectДва аргумента, это две функции.

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

// 判断变量否为function
const isFunction = variable => typeof variable === 'function'

Во-первых, мы определяемMyPromiseизClass, который принимает функциюhandleкак параметр

class MyPromise {
  constructor (handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
  }
}

смотреть дальше вниз

2. Promiseстатус и ценность

PromiseОбъекты существуют в следующих трех состояниях:

  • Pending(进行中)

  • Fulfilled(已成功)

  • Rejected(已失败)

состояние можно определить толькоPendingстатьFulfilledили поPendingстатьRejected, и состояние не изменится после изменения состояния, оно сохранит это состояние навсегда.

PromiseЗначение — это значение, передаваемое функции обратного вызова при изменении состояния.

вышеhandleфункция содержитresolveиrejectДва параметра, это две функции, которые можно использовать для измененияPromiseсостояние и входящиеPromiseзначение

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('FULFILLED')
  }, 1000)
})

здесьresolveвходящий"FULFILLED"этоPromiseзначение

resolveиreject

  • resolve: изменить состояние объекта Promise сPending(进行中)статьFulfilled(已成功)
  • reject: изменить состояние объекта Promise сPending(进行中)статьRejected(已失败)
  • resolveиrejectВы можете передать любой тип значения в качестве аргумента, указывая, чтоPromiseобъект успешно(Fulfilled)и потерпеть неудачу(Rejected)значение

понялPromiseСостояние и значение , далее имеемMyPromiseДобавьте атрибуты состояния и значения

Сначала определите три константы, чтобы отметить три состояния объекта Promise.

// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

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

class MyPromise {
  constructor (handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
    // 添加状态
    this._status = PENDING
    // 添加状态
    this._value = undefined
    // 执行handle
    try {
      handle(this._resolve.bind(this), this._reject.bind(this)) 
    } catch (err) {
      this._reject(err)
    }
  }
  // 添加resovle时执行的函数
  _resolve (val) {
    if (this._status !== PENDING) return
    this._status = FULFILLED
    this._value = val
  }
  // 添加reject时执行的函数
  _reject (err) { 
    if (this._status !== PENDING) return
    this._status = REJECTED
    this._value = err
  }
}

Вот и всеPromiseСостояние и значение меняются. Давайте поговорим оPromiseОсновной:thenметод

3. Promiseизthenметод

PromiseобъектthenМетод принимает два параметра:

promise.then(onFulfilled, onRejected)

необязательный параметр

onFulfilledиonRejectedявляются необязательными параметрами.

  • еслиonFulfilledилиonRejectedэто не функция, ее нужно игнорировать

onFulfilledхарактеристика

еслиonFulfilledэто функция:

  • когдаpromiseДолжен вызываться, когда статус меняется на успех, его первый параметрpromiseЗначение, переданное для статуса успеха (resolveзначение, переданное во время выполнения)
  • существуетpromiseЕго нельзя вызвать, пока не изменится состояние
  • Его нельзя вызывать более одного раза

onRejectedхарактеристика

еслиonRejectedэто функция:

  • когдаpromiseДолжен вызываться при изменении статуса на сбой, его первый параметрpromiseЗначение, переданное для состояния отказа (rejectзначение, переданное во время выполнения)
  • существуетpromiseЕго нельзя вызвать, пока не изменится состояние
  • Его нельзя вызывать более одного раза

несколько вызовов

   thenметоды могут быть использованы одним и тем жеpromiseОбъект вызывается несколько раз

  • когдаpromiseВ состоянии успеха всеonFulfilledОн должен быть отозван по порядку в соответствии с порядком его регистрации.
  • когдаpromiseВ неисправном состоянии всеonRejectedОн должен быть отозван по порядку в соответствии с порядком его регистрации.

возвращение

thenметод должен возвращать новыйpromiseобъект

promise2 = promise1.then(onFulfilled, onRejected);

следовательноpromiseПоддержка связанных вызовов

promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);

участие здесьPromiseПравила выполнения, включая механизмы «передачи по значению» и «отлова ошибок»:

1. ЕслиonFulfilledилиonRejectedвернуть значениеx, затем выполните следующееPromiseПроцесс разрешения:[[Resolve]](promise2, x)

  • какxне дляPromise, затем сделайтеxвернулся прямо как новыйPromiseстоимость объекта, т. е. новыйonFulfilledилиonRejectedпараметры функции.
  • какxзаPromise, то последняя функция обратного вызова будет ждатьPromiseобъект (т.x) будет вызываться при изменении состояния ) , а новыйPromiseстатус иxстатус такой же.

Для облегчения понимания используется следующий пример:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
  // 返回一个普通值
  return '这里返回一个普通值'
})
promise2.then(res => {
  console.log(res) //1秒后打印出:这里返回一个普通值
})
let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
  // 返回一个Promise对象
  return new Promise((resolve, reject) => {
    setTimeout(() => {
     resolve('这里返回一个Promise')
    }, 2000)
  })
})
promise2.then(res => {
  console.log(res) //3秒后打印出:这里返回一个Promise
})

2. ЕслиonFulfilledилиonRejectedбросить исключениеe,ноpromise2должен потерпеть неудачу(Rejected)и вернуть значение ошибкиe,Например:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then(res => {
  throw new Error('这里抛出一个异常e')
})
promise2.then(res => {
  console.log(res)
}, err => {
  console.log(err) //1秒后打印出:这里抛出一个异常e
})

3. ЕслиonFulfilledне является функцией иpromise1Статус - успех(Fulfilled),promise2должен быть успешным(Fulfilled)и вернутьсяpromise1Успешное значение, например:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
  console.log(res) // 1秒后打印出:success
}, err => {
  console.log(err)
})

4. ЕслиonRejectedне является функцией иpromise1статус не выполнен(Rejected),promise2должен потерпеть неудачу(Rejected)и вернутьсяpromise1Неверные значения, такие как:

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('fail')
  }, 1000)
})
promise2 = promise1.then(res => res, '这里的onRejected本来是一个函数,但现在不是')
promise2.then(res => {
  console.log(res)
}, err => {
  console.log(err)  // 1秒后打印出:fail
})

По вышеизложенным правилам приходим к совершенствуMyPromise

Исправлятьconstructor: увеличить очередь выполнения

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

constructor (handle) {
  if (!isFunction(handle)) {
    throw new Error('MyPromise must accept a function as a parameter')
  }
  // 添加状态
  this._status = PENDING
  // 添加状态
  this._value = undefined
  // 添加成功回调函数队列
  this._fulfilledQueues = []
  // 添加失败回调函数队列
  this._rejectedQueues = []
  // 执行handle
  try {
    handle(this._resolve.bind(this), this._reject.bind(this)) 
  } catch (err) {
    this._reject(err)
  }
}

добавить затем метод

Во-первых,thenвернуть новыйPromiseобъект, а функцию обратного вызова необходимо добавить в очередь выполнения

// 添加then方法
then (onFulfilled, onRejected) {
  const { _value, _status } = this
  switch (_status) {
    // 当状态为pending时,将then方法回调函数加入执行队列等待执行
    case PENDING:
      this._fulfilledQueues.push(onFulfilled)
      this._rejectedQueues.push(onRejected)
      break
    // 当状态已经改变时,立即执行对应的回调函数
    case FULFILLED:
      onFulfilled(_value)
      break
    case REJECTED:
      onRejected(_value)
      break
  }
  // 返回一个新的Promise对象
  return new MyPromise((onFulfilledNext, onRejectedNext) => {
  })
}

который вернул новыйPromiseКогда объект меняет состояние? В какое состояние он переходит?

Согласно вышеизложенномуthenПравила метода, мы знаем, что новый вернулсяPromiseСостояние объекта зависит от текущегоthenВыполнение функции обратного вызова метода и возвращаемое значение, напримерthenЯвляется ли параметр функцией, есть ли ошибка при выполнении функции обратного вызова и является ли возвращаемое значениеPromiseобъект.

Давайте дальше улучшатьthenметод:

// 添加then方法
then (onFulfilled, onRejected) {
  const { _value, _status } = this
  // 返回一个新的Promise对象
  return new MyPromise((onFulfilledNext, onRejectedNext) => {
    // 封装一个成功时执行的函数
    let fulfilled = value => {
      try {
        if (!isFunction(onFulfilled)) {
          onFulfilledNext(value)
        } else {
          let res =  onFulfilled(value);
          if (res instanceof MyPromise) {
            // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
            res.then(onFulfilledNext, onRejectedNext)
          } else {
            //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
            onFulfilledNext(res)
          }
        }
      } catch (err) {
        // 如果函数执行出错,新的Promise对象的状态为失败
        onRejectedNext(err)
      }
    }
    // 封装一个失败时执行的函数
    let rejected = error => {
      try {
        if (!isFunction(onRejected)) {
          onRejectedNext(error)
        } else {
            let res = onRejected(error);
            if (res instanceof MyPromise) {
              // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
              res.then(onFulfilledNext, onRejectedNext)
            } else {
              //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
              onFulfilledNext(res)
            }
        }
      } catch (err) {
        // 如果函数执行出错,新的Promise对象的状态为失败
        onRejectedNext(err)
      }
    }
    switch (_status) {
      // 当状态为pending时,将then方法回调函数加入执行队列等待执行
      case PENDING:
        this._fulfilledQueues.push(fulfilled)
        this._rejectedQueues.push(rejected)
        break
      // 当状态已经改变时,立即执行对应的回调函数
      case FULFILLED:
        fulfilled(_value)
        break
      case REJECTED:
        rejected(_value)
        break
    }
  })
}

Эту часть может быть нелегко понять, читатели должны объединить вышеперечисленноеthenПодробно анализируются правила метода.

Затем измените_resolveи_reject: последовательно выполнять функции в очереди

когдаresolveилиrejectКогда метод выполняется, мы последовательно извлекаем функции из успешной или неудачной очереди задач, чтобы начать выполнение, и очищаем очередь для достиженияthenМетод вызывается несколько раз, и код реализации выглядит следующим образом:

// 添加resovle时执行的函数
_resolve (val) {
  if (this._status !== PENDING) return
  // 依次执行成功队列中的函数,并清空队列
  const run = () => {
    this._status = FULFILLED
    this._value = val
    let cb;
    while (cb = this._fulfilledQueues.shift()) {
      cb(val)
    }
  }
  // 为了支持同步的Promise,这里采用异步调用
  setTimeout(() => run(), 0)
}
// 添加reject时执行的函数
_reject (err) { 
  if (this._status !== PENDING) return
  // 依次执行失败队列中的函数,并清空队列
  const run = () => {
    this._status = REJECTED
    this._value = err
    let cb;
    while (cb = this._rejectedQueues.shift()) {
      cb(err)
    }
  }
  // 为了支持同步的Promise,这里采用异步调用
  setTimeout(run, 0)
}

Здесь тоже есть частный случай, когдаresolveВ метод передается параметрPromiseобъект,PromiseСостояние объекта определяет текущийPromiseсостояние объекта.

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

В приведенном выше кодеp1иp2обаPromiseпример, ноp2изresolveметод будетp1В качестве параметра результатом одной асинхронной операции является результат другой асинхронной операции.

Обратите внимание, что в это времяp1статус будет переданp2, это,p1статус определяетp2статус. еслиp1СтатусPending,Такp2Функция обратного вызова будет ждатьp1состояние меняется; еслиp1Статус ужеFulfilledилиRejected,Такp2Функция обратного вызова будет выполнена немедленно.

давайте изменим_resolveдля поддержки таких функций

  // 添加resovle时执行的函数
  _resolve (val) {
    const run = () => {
      if (this._status !== PENDING) return
      // 依次执行成功队列中的函数,并清空队列
      const runFulfilled = (value) => {
        let cb;
        while (cb = this._fulfilledQueues.shift()) {
          cb(value)
        }
      }
      // 依次执行失败队列中的函数,并清空队列
      const runRejected = (error) => {
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(error)
        }
      }
      /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
        当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
      */
      if (val instanceof MyPromise) {
        val.then(value => {
          this._value = value
          this._status = FULFILLED
          runFulfilled(value)
        }, err => {
          this._value = err
          this._status = REJECTED
          runRejected(err)
        })
      } else {
        this._value = val
        this._status = FULFILLED
        runFulfilled(val)
      }
    }
    // 为了支持同步的Promise,这里采用异步调用
    setTimeout(run, 0)
  }

Такой промис в основном реализован, теперь добавим некоторые другие методы

catchметод

эквивалентно вызовуthenметод, а только пройти вRejectedфункция обратного вызова состояния

// 添加catch方法
catch (onRejected) {
  return this.then(undefined, onRejected)
}

статическийresolveметод

// 添加静态resolve方法
static resolve (value) {
  // 如果参数是MyPromise实例,直接返回这个实例
  if (value instanceof MyPromise) return value
  return new MyPromise(resolve => resolve(value))
}

статическийrejectметод

// 添加静态reject方法
static reject (value) {
  return new MyPromise((resolve ,reject) => reject(value))
}

статическийallметод

// 添加静态all方法
static all (list) {
  return new MyPromise((resolve, reject) => {
    /**
     * 返回值的集合
     */
    let values = []
    let count = 0
    for (let [i, p] of list.entries()) {
      // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
      this.resolve(p).then(res => {
        values[i] = res
        count++
        // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
        if (count === list.length) resolve(values)
      }, err => {
        // 有一个被rejected时返回的MyPromise状态就变成rejected
        reject(err)
      })
    }
  })
}

статическийraceметод

// 添加静态race方法
static race (list) {
  return new MyPromise((resolve, reject) => {
    for (let p of list) {
      // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
      this.resolve(p).then(res => {
        resolve(res)
      }, err => {
        reject(err)
      })
    }
  })
}

finallyметод

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

finally (cb) {
  return this.then(
    value  => MyPromise.resolve(cb()).then(() => value),
    reason => MyPromise.resolve(cb()).then(() => { throw reason })
  );
};

такой полныйPromsieЭто сделано, всеPromiseПринцип также понятен, что может сделать нас более понятными при использовании Promise.

Полный код выглядит следующим образом

  // 判断变量否为function
  const isFunction = variable => typeof variable === 'function'
  // 定义Promise的三种状态常量
  const PENDING = 'PENDING'
  const FULFILLED = 'FULFILLED'
  const REJECTED = 'REJECTED'

  class MyPromise {
    constructor (handle) {
      if (!isFunction(handle)) {
        throw new Error('MyPromise must accept a function as a parameter')
      }
      // 添加状态
      this._status = PENDING
      // 添加状态
      this._value = undefined
      // 添加成功回调函数队列
      this._fulfilledQueues = []
      // 添加失败回调函数队列
      this._rejectedQueues = []
      // 执行handle
      try {
        handle(this._resolve.bind(this), this._reject.bind(this)) 
      } catch (err) {
        this._reject(err)
      }
    }
    // 添加resovle时执行的函数
    _resolve (val) {
      const run = () => {
        if (this._status !== PENDING) return
        // 依次执行成功队列中的函数,并清空队列
        const runFulfilled = (value) => {
          let cb;
          while (cb = this._fulfilledQueues.shift()) {
            cb(value)
          }
        }
        // 依次执行失败队列中的函数,并清空队列
        const runRejected = (error) => {
          let cb;
          while (cb = this._rejectedQueues.shift()) {
            cb(error)
          }
        }
        /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
          当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
        */
        if (val instanceof MyPromise) {
          val.then(value => {
            this._value = value
            this._status = FULFILLED
            runFulfilled(value)
          }, err => {
            this._value = err
            this._status = REJECTED
            runRejected(err)
          })
        } else {
          this._value = val
          this._status = FULFILLED
          runFulfilled(val)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加reject时执行的函数
    _reject (err) { 
      if (this._status !== PENDING) return
      // 依次执行失败队列中的函数,并清空队列
      const run = () => {
        this._status = REJECTED
        this._value = err
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(err)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加then方法
    then (onFulfilled, onRejected) {
      const { _value, _status } = this
      // 返回一个新的Promise对象
      return new MyPromise((onFulfilledNext, onRejectedNext) => {
        // 封装一个成功时执行的函数
        let fulfilled = value => {
          try {
            if (!isFunction(onFulfilled)) {
              onFulfilledNext(value)
            } else {
              let res =  onFulfilled(value);
              if (res instanceof MyPromise) {
                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                res.then(onFulfilledNext, onRejectedNext)
              } else {
                //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                onFulfilledNext(res)
              }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        // 封装一个失败时执行的函数
        let rejected = error => {
          try {
            if (!isFunction(onRejected)) {
              onRejectedNext(error)
            } else {
                let res = onRejected(error);
                if (res instanceof MyPromise) {
                  // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                  onFulfilledNext(res)
                }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        switch (_status) {
          // 当状态为pending时,将then方法回调函数加入执行队列等待执行
          case PENDING:
            this._fulfilledQueues.push(fulfilled)
            this._rejectedQueues.push(rejected)
            break
          // 当状态已经改变时,立即执行对应的回调函数
          case FULFILLED:
            fulfilled(_value)
            break
          case REJECTED:
            rejected(_value)
            break
        }
      })
    }
    // 添加catch方法
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }
    // 添加静态resolve方法
    static resolve (value) {
      // 如果参数是MyPromise实例,直接返回这个实例
      if (value instanceof MyPromise) return value
      return new MyPromise(resolve => resolve(value))
    }
    // 添加静态reject方法
    static reject (value) {
      return new MyPromise((resolve ,reject) => reject(value))
    }
    // 添加静态all方法
    static all (list) {
      return new MyPromise((resolve, reject) => {
        /**
         * 返回值的集合
         */
        let values = []
        let count = 0
        for (let [i, p] of list.entries()) {
          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
          this.resolve(p).then(res => {
            values[i] = res
            count++
            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
            if (count === list.length) resolve(values)
          }, err => {
            // 有一个被rejected时返回的MyPromise状态就变成rejected
            reject(err)
          })
        }
      })
    }
    // 添加静态race方法
    static race (list) {
      return new MyPromise((resolve, reject) => {
        for (let p of list) {
          // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
          this.resolve(p).then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        }
      })
    }
    finally (cb) {
      return this.then(
        value  => MyPromise.resolve(cb()).then(() => value),
        reason => MyPromise.resolve(cb()).then(() => { throw reason })
      );
    }
  }

Если вы считаете, что это нормально, ставьте палец вверх, добавляйте в закладки и поехали.