Эта статья предназначена в основном для изучения
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 })
);
}
}
Если вы считаете, что это нормально, ставьте палец вверх, добавляйте в закладки и поехали.