После прочтения принцип написания промиса от руки - самая понятная версия! ! !

внешний интерфейс JavaScript
После прочтения принцип написания промиса от руки - самая понятная версия! ! !

предисловие

Привет всем, я Линь Сансинь, я думаю, что все использовали его в повседневной разработке.Promise, у меня всегда была мечта, чтоСамыми простыми словами расскажи самые сложные знания, поэтому я поставилЛегко понятьПоставьте это на первое место, сегодня я возьму вас, чтобы добиться следующего почеркаОбещай это, Я думаю, все поймут с первого взгляда.

image.png

решить и отклонить

Давайте посмотрим на кусок кода Promise:

let p1 = new Promise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
console.log('p1', p1)

let p2 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')
})
console.log('p2', p2)

let p3 = new Promise((resolve, reject) => {
    throw('报错')
})
console.log('p3', p3)

Так что же будет на выходе? Пожалуйста, посмотри:

截屏2021-08-01 上午11.53.33.png

Здесь раскрываются четыре точки знаний:

  • 1. Казненresolve, состояние Promise станетfulfilled
  • 2. Казненreject, состояние Promise станетrejected
  • 3. Обещания начинаются только с第一次为准, первый успешный永久дляfulfilled, первая ошибка всегда будет указываться какrejected
  • 4. В обещанииthrowЕсли слова эквивалентны выполнениюreject

Затем мы поставили эти четыре знания шаг за шагом, чтобы добиться этого! ! !

1. Решить и отклонить

Всем следует обратить внимание: начальное состояние Promisepending

Важным шагом здесь являетсяresolve和reject的绑定this, зачем привязыватьthisШерстяная ткань? Это для решения и отклоненияthis指向всегда указывать на текущийMyPromise实例, чтобы предотвратить изменения при изменении среды выполнения функции

class MyPromise {
    // 构造方法
    constructor(executor) {

        // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
        // 执行传进来的函数
        executor(this.resolve, this.reject)
    }

    initBind() {
        // 初始化this
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }

    initValue() {
        // 初始化值
        this.PromiseResult = null // 终值
        this.PromiseState = 'pending' // 状态
    }

    resolve(value) {
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
    }

    reject(reason) {
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
    }
}

Давайте протестируем код:

const test1 = new MyPromise((resolve, reject) => {
    resolve('成功')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }

const test2 = new MyPromise((resolve, reject) => {
    reject('失败')
})
console.log(test2) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

2. Состояние неизменно

На самом деле приведенный выше код проблематичен, в чем проблема? посмотри:

const test1 = new MyPromise((resolve, reject) => {
    resolve('成功')
    reject('失败')
})
console.log(test1) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

Правильное состояние должно бытьfulfilled,оказаться成功, явно нет以第一次为准

Как я уже говорил, промисы начинаются только с第一次为准, первый успешный永久дляfulfilled, первая ошибка всегда будет указываться какrejected, каков конкретный процесс? Я нарисовал для вас картинку:

Обещания имеют три состояния:

  • pending: Ожидание, это начальное состояние
  • fulfilled: состояние успеха
  • rejected: статус отказа

Как только состояние изменится сpendingсталиfulfilled或者rejected, то состояние этого экземпляра Promise мертво.截屏2021-08-01 下午12.33.10.png

На самом деле это очень легко реализовать, просто добавьте условие суждения:

    resolve(value) {
        // state是不可变的
+        if (this.PromiseState !== 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
    }

    reject(reason) {
        // state是不可变的
+        if (this.PromiseState !== 'pending') return
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
    }

Давайте посмотрим на эффект:

const test1 = new MyPromise((resolve, reject) => {
    // 只以第一次为准
    resolve('成功')
    reject('失败')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }

3. throw

截屏2021-08-01 下午12.57.17.png

Обещай тамthrowэквивалентно выполнениюreject. это использоватьtry catchохватывать

+        try {
            // 执行传进来的函数
            executor(this.resolve, this.reject)
+        } catch (e) {
            // 捕捉到错误直接执行reject
+            this.reject(e)
+        }

Давайте посмотрим на эффект:

const test3 = new MyPromise((resolve, reject) => {
    throw('失败')
})
console.log(test3) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

then

Обычно мы используем метод then следующим образом:

// 马上输出 ”成功“
const p1 = new Promise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

// 1秒后输出 ”失败“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('失败')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => 2 * res, err => console.log(err))
  .then(res => console.log(res), err => console.log(err))

Эти знания можно суммировать:

  • затем получает два обратных вызова, один成功回调,один失败回调
  • Когда состояние обещанияfulfilledвоплощать в жизнь成功回调,дляrejectedвоплощать в жизнь失败回调
  • Если разрешение или отклонение находится в таймере,则定时器结束后再执行then
  • затем поддержите链式调用, затем выполняется следующий受上一次then返回值的影响

Пойдем шаг за шагом, чтобы понять это.

1. Реализуйте затем

    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected
        
        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

        if (this.PromiseState === 'fulfilled') {
            // 如果当前为成功状态,执行第一个回调
            onFulfilled(this.PromiseResult)
        } else if (this.PromiseState === 'rejected') {
            // 如果当前为失败状态,执行第二哥回调
            onRejected(this.PromiseResult)
        }

    }

Давайте посмотрим на эффект:

// 输出 ”成功“
const test = new MyPromise((resolve, reject) => {
    resolve('成功')
}).then(res => console.log(res), err => console.log(err))

2. Таймер ситуации

Выше мы достиглиthenОсновные функции. что если定时器Как насчет ситуации?

Или этот код, как мы можем гарантировать, что обратный вызов ошибки в then будет выполнен через 1 секунду?

// 1秒后输出 ”成功“
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('失败')
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

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

截屏2021-08-01 下午9.05.24.png

То есть в течение этой 1 секунды мы можем сначала сохранить два обратных вызова в then, а затем подождать, пока через 1 секунду не будет выполнено разрешение или отклонение, а затем оценить статус и принять решение о выполнении двух только что сохраненных обратных вызовов. Перезвоните.

Итак, вопрос в том, как мы узнаем, что текущая 1 секунда не была завершена или даже не началась? На самом деле, очень хорошо судить, пока статусpending, это доказывает, что таймер не истек, потому что если таймер истекает, то состояние точно неpending, ноfulfilled或者rejected

Так что же используется для сохранения этих обратных вызовов? Рекомендуется использовать数组, потому что экземпляр обещания может多次then, используйте массив для сохранения по одному

    initValue() {
        // 初始化值
        this.PromiseResult = null // 终值
        this.PromiseState = 'pending' // 状态
+        this.onFulfilledCallbacks = [] // 保存成功回调
+        this.onRejectedCallbacks = [] // 保存失败回调
    }

    resolve(value) {
        // state是不可变的
        if (this.PromiseState !== 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
        // 执行保存的成功回调
+        while (this.onFulfilledCallbacks.length) {
+            this.onFulfilledCallbacks.shift()(this.PromiseResult)
+        }
    }

    reject(reason) {
        // state是不可变的
        if (this.PromiseState !== 'pending') return
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
        // 执行保存的失败回调
+        while (this.onRejectedCallbacks.length) {
+            this.onRejectedCallbacks.shift()(this.PromiseResult)
+        }
    }
    
    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

        if (this.PromiseState === 'fulfilled') {
            // 如果当前为成功状态,执行第一个回调
            onFulfilled(this.PromiseResult)
        } else if (this.PromiseState === 'rejected') {
            // 如果当前为失败状态,执行第二哥回调
            onRejected(this.PromiseResult)
+        } else if (this.PromiseState === 'pending') {
+            // 如果状态为待定状态,暂时保存两个回调
+            this.onFulfilledCallbacks.push(onFulfilled.bind(this))
+            this.onRejectedCallbacks.push(onRejected.bind(this))
+        }

    }

После добавления приведенного выше кода давайте посмотрим на эффект таймера:

const test2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功') // 1秒后输出 成功
        // resolve('成功') // 1秒后输出 失败
    }, 1000)
}).then(res => console.log(res), err => console.log(err))

3. Связанные вызовы

затем поддержите链式调用, затем выполняется следующий受上一次then返回值的影响, чтобы дать вам пример:

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => 2 * res, err => console.log(err))
    .then(res => console.log(res), err => console.log(err))

// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err))
    .then(res => console.log(res), err => console.log(err))

Из приведенного выше примера мы можем получить несколько точек знаний:

  • 1. Сам метод then возвращает новый объект Promise
  • 2. Если возвращаемое значение является объектом обещания, возвращаемое значение успешно, и новое обещание выполнено успешно.
  • 3. Если возвращаемое значение является объектом-обещанием, возвращаемое значение — сбой, а новое обещание — сбой.
  • 4. Если возвращаемое значение не является объектом-обещанием, новый объект-обещание считается успешным, и значением является это возвращаемое значение.

Мы знаем, что then — это метод в Promise, так как же реализовать then и then? Очень просто, затем возвращаетPromise对象Вот и все, вы можете убедиться, что вы можете продолжить выполнение после этого:

截屏2021-08-01 下午9.06.02.png

Код:

    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }


        var thenPromise = new MyPromise((resolve, reject) => {

            const resolvePromise = cb => {
                try {
                    const x = cb(this.PromiseResult)
                    if (x === thenPromise) {
                        // 不能返回自身哦
                        throw new Error('不能返回自身。。。')
                    }
                    if (x instanceof MyPromise) {
                        // 如果返回值是Promise
                        // 如果返回值是promise对象,返回值为成功,新promise就是成功
                        // 如果返回值是promise对象,返回值为失败,新promise就是失败
                        // 谁知道返回的promise是失败成功?只有then知道
                        x.then(resolve, reject)
                    } else {
                        // 非Promise就直接成功
                        resolve(x)
                    }
                } catch (err) {
                    // 处理报错
                    reject(err)
                    throw new Error(err)
                }
            }

            if (this.PromiseState === 'fulfilled') {
                // 如果当前为成功状态,执行第一个回调
                resolvePromise(onFulfilled)
            } else if (this.PromiseState === 'rejected') {
                // 如果当前为失败状态,执行第二个回调
                resolvePromise(onRejected)
            } else if (this.PromiseState === 'pending') {
                // 如果状态为待定状态,暂时保存两个回调
                // 如果状态为待定状态,暂时保存两个回调
                this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
                this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
            }
        })

        // 返回这个包装的Promise
        return thenPromise

    }

Теперь каждый может попробовать, как эффект, все хотятпостучи и попробуйОй:


const test3 = new MyPromise((resolve, reject) => {
  resolve(100) // 输出 状态:成功 值: 200
  // reject(100) // 输出 状态:失败 值:300
}).then(res => 2 * res, err => 3 * err)
  .then(res => console.log('成功', res), err => console.log('失败', err))

const test4 = new MyPromise((resolve, reject) => {
  resolve(100) // 输出 状态:失败 值:300
  // reject(100) // 输出 状态:成功 值:200
  // 这里可没搞反哦。真的搞懂了,就知道了为啥这里是反的
}).then(res => new MyPromise((resolve, reject) => reject(2 * res)), err => new MyPromise((resolve, reject) => resolve(3 * res)))
  .then(res => console.log('成功', res), err => console.log('失败', err))

4. Микрозадачи

Видимыйjs执行机制Братья знают, что тогда метод微任务, Что такое микро задача? На самом деле, не имеет значения, если вы не знаете, я дам вам знать на следующем примере:

const p = new Promise((resolve, reject) => {
    resolve(1)
}).then(res => console.log(res), err => console.log(err))

console.log(2)

输出顺序是 2 1

Почему не 1 2? Потому что это микрозадача. . . Точно так же мы должны добавить эту функцию в наш MyPromise (здесь я использую таймер, не обращайте на меня внимания)

просто позвольresolvePromise函数Просто сделайте это асинхронно

 const resolvePromise = cb => {
    setTimeout(() => {
        try {
            const x = cb(this.PromiseResult)
            if (x === thenPromise) {
                // 不能返回自身哦
                throw new Error('不能返回自身。。。')
            }
            if (x instanceof MyPromise) {
                // 如果返回值是Promise
                // 如果返回值是promise对象,返回值为成功,新promise就是成功
                // 如果返回值是promise对象,返回值为失败,新promise就是失败
                // 谁知道返回的promise是失败成功?只有then知道
                x.then(resolve, reject)
            } else {
                // 非Promise就直接成功
                resolve(x)
            }
        } catch (err) {
            // 处理报错
            reject(err)
            throw new Error(err)
        }
    })
}

Взгляните на эффект:

const test4 = new MyPromise((resolve, reject) => {
    resolve(1)
}).then(res => console.log(res), err => console.log(err))

console.log(2)

输出顺序 2 1

Другие методы

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

all

  • Получить массив обещаний, если в массиве есть элемент, не являющийся обещанием, этот элемент считается успешным
  • Если все обещания выполнены успешно, вернуть массив успешных результатов.
  • Если обещание не выполняется, вернуть этот результат ошибки
    static all(promises) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            const addData = (index, value) => {
                result[index] = value
                count++
                if (count === promises.length) resolve(result)
            }
            promises.forEach((promise, index) => {
                if (promise instanceof MyPromise) {
                    promise.then(res => {
                        addData(index, res)
                    }, err => reject(err))
                } else {
                    addData(index, promise)
                }
            })
        })
    }

race

  • Получить массив обещаний, если в массиве есть элемент, не являющийся обещанием, этот элемент считается успешным
  • Какой промис быстрее всего получает результат, возвращает этот результат, независимо от того, успешен он или нет
    static race(promises) {
        return new MyPromise((resolve, reject) => {
            promises.forEach(promise => {
                if (promise instanceof MyPromise) {
                    promise.then(res => {
                        resolve(res)
                    }, err => {
                        reject(err)
                    })
                } else {
                    resolve(promise)
                }
            })
        })
    }

allSettled

  • Получить массив обещаний, если в массиве есть элемент, не являющийся обещанием, этот элемент считается успешным
  • Соберите результаты каждого промиса в массив и верните
    static allSettled(promises) {
        return new Promise((resolve, reject) => {
            const res = []
            let count = 0
            const addData = (status, value, i) => {
                res[i] = {
                    status,
                    value
                }
                count++
                if (count === promises.length) {
                    resolve(res)
                }
            }
            promises.forEach((promise, i) => {
                if (promise instanceof MyPromise) {
                    promise.then(res => {
                        addData('fulfilled', res, i)
                    }, err => {
                        addData('rejected', err, i)
                    })
                } else {
                    addData('fulfilled', promise, i)
                }
            })
        })
    }

any

любое противоположно всему

  • Получить массив обещаний, если в массиве есть элемент, не являющийся обещанием, этот элемент считается успешным
  • Если обещание выполнено успешно, вернуть этот результат успеха
  • Если все обещания не выполняются, выдать ошибку
    static any(promises) {
        return new Promise((resolve, reject) => {
            let count = 0
            promises.forEach((promise) => {
                promise.then(val => {
                    resolve(val)
                }, err => {
                    count++
                    if (count === promises.length) {
                        reject(new AggregateError('All promises were rejected'))
                    }
                })
            })
        })
    }
}

Эпилог

Больше не боитесь, что интервьюер спросит у вас принцип Обещания хахахаха😁

Если вы считаете, что эта статья вам немного поможет, поставьте лайк и поддержите Линь Сансиня, ха-ха.

Если вы хотите изучать интерфейс или рыбачить вместе, вы можете добавить меня, присоединиться к моей группе по изучению рыбы, нажмите здесь. ---> коснуться точки кипения рыбы

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