Изучите основы обещаний и рукописные обещания

Promise

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

Узнать обещания

Значение обещаний

PromiseЭто решение для асинхронного программирования, ES6 вписал его в стандарт языка. так называемыйPromiseЭто контейнер, в котором хранятся события (обычно асинхронные операции), которые завершатся в будущем.результат.

PromiseОбъекты имеют следующие две характеристики:

  • На состояние объекта не влияет внешний мир.PromiseОбъект представляет собой асинхронную операцию и имеет три состояния:pending(в ходе выполнения),fulfilled/resolved(удалось),rejected(не удалось). Только результат асинхронной операции может определить текущее состояние, и никакая другая операция не может изменить это состояние.
  • Как только состояние изменилось, оно больше никогда не изменится, и этот результат можно получить в любое время.PromiseЕсть только две возможности для изменения состояния объекта: отpendingсталиfulfilledи изpendingсталиrejected. Пока эти две ситуации имеют место, состояние будет затвердевшим и не изменится, и всегда будет поддерживать этот результат, который называетсяresolved(уже доработано). Если изменение уже произошло, выPromiseДобавьте к объекту функцию обратного вызова, и вы сразу же получите этот результат.

PromiseПреимущества:

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

Основное использование

ES6 заявляет,PromiseОбъект — это конструктор, используемый для генерацииPromiseпример.

const promise = new Promise((resolve,reject)=>{
//此处执行一些异步操作(调用后台API,定时器等)
 if(/*异步操作成功*/){
     resolve(value);
 }else{
     reject(error)
 }
}) 
//其中两个函数的参数值分别为成功和失败后想要传递的结果

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

resolveФункция функции состоит в том, чтобыPromiseСостояние объекта меняется с «Не завершено» на «Успешно» (т.е. сpendingсталиresolved), вызывается при успешном выполнении асинхронной операции, и результат асинхронной операции передается в качестве параметра;rejectФункция функции состоит в том, чтобыPromiseСостояние объекта меняется с «Незавершенный» на «Неудачный» (т.е. сpendingсталиrejected), вызываемый при сбое асинхронной операции, и передает сообщение об ошибке асинхронной операции в качестве параметра.

thenМетод может принимать две функции обратного вызова в качестве параметров. Первая функция обратного вызоваPromiseСостояние объекта становитсяresolvedПри вызове вторая функция обратного вызоваPromiseСостояние объекта становитсяrejectedкогда звонили. Среди них вторая функция не является обязательной и не обязательно. Обе функции принимаютPromiseЗначение, переданное из объекта в качестве параметра.

promise.then(res=>{
    //对于成功回调接受的数据做处理
},err=>{
    //对于失败的回调数据做处理
})

Примечание:PromiseОн будет выполнен, как только будет создан.

Promise.prototype.then() Promiseэкземпляр имеетthenметод, то естьthenМетод определен на объекте-прототипеPromise.prototypeвыше, его функция состоит в том, чтобыPromiseФункция обратного вызова, когда экземпляр добавляет изменения состояния. Я сказал раньше,thenПервый параметр методаresolvedФункция обратного вызова состояния, второй параметр (необязательный)是rejectedФункция обратного вызова статуса.

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

прикованныйthen, вы можете указать набор функций обратного вызова, которые будут вызываться по порядку. (в ES7async/await) Также могут быть достигнуты цепные вызовы, кроме того,PromiseизallМетоды могут выполняться параллельно.

понимать основыPromiseа такжеthenПосле этого мы можем создать свой собственныйPromise.

Рукописное обещание

напиши первымPromiseконструктор, из вышеперечисленногоPromiseИз использования видно, что его параметр является функцией, также известной как функция-исполнитель (executor), и функция-исполнитель будет вызвана сразу, и функция-исполнитель также получит два параметра, оба из которых являются функциями .

function Promise(executor) {
    executor(resolve, reject);
}

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

Promise.prototype.then=function(onResolved,onRejected){
    
}

продолжать писатьPromiseфункцию, потому чтоnewИсходящий экземпляр имеет состояние по умолчаниюpending, то через исполнителяexecutorвоплощать в жизньresolveа такжеrejectДве функции для изменения состояния.

function Promise(executor) {
    let self=this;                   //保留this。防止后面方法出现this只想不明的问题
    self.status='pending';           //promise的默认状态是pending

    function resolve(){
        self.status='resolved';      //成功函数将其状态修改为resolved
    }
    function reject(){
        self.status='rejected';      //失败函数将其函数修改为rejected
    }
    executor(resolve, reject);
}

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

function Promise(executor) {
    let self = this;                       //保留this。防止后面方法出现this只想不明的问题
    self.status = 'pending';               //promise的默认状态是pending
    self.success = undefined;              //保存成功回调传递的值
    self.error = undefined;                //保存失败回调传递的值

    function resolve() {
        if (self.status === 'pending') {
            self.status = 'resolved';      //成功函数将其状态修改为resolved
        }
    }
    function reject() {
        if (self.status === 'pending') {
            self.status = 'rejected';      //失败函数将其函数修改为rejected
        }
    }
    executor(resolve, reject);
}

После этого вам нужно сохранить результаты успеха или неудачи после вызова

function Promise(executor) {
    let self = this;                       //保留this。防止后面方法出现this只想不明的问题
    self.status = 'pending';               //promise的默认状态是pending
    self.success = undefined;              //保存成功回调传递的值
    self.error = undefined;                //保存失败回调传递的值

    function resolve(success) {
        if (self.status === 'pending') {
            self.status = 'resolved';      //成功函数将其状态修改为resolved
            self.success=success;          //将成功的值保存起来
        }
    }
    function reject(error) {
        if (self.status === 'pending') {
            self.status = 'rejected';      //失败函数将其函数修改为rejected
            self.error=error;              //将失败的值保存起来
        }
    }
    executor(resolve, reject);
}

Вот практический пример (Express использует Promise для сохранения возвращаемого значения)

Примечание. В этом примере используется асинхронная обработка функций, связанные вызовы, и он помещен здесь только для иллюстрации приведенных выше понятий.

когда исполнитель звонитresolveПосле функции,thenВыполняется первый параметр в функции (успешный обратный вызов), и сохраненное значение передается вthenПервая функция в качестве аргумента и при вызове исполнителяrejectПосле функции,thenВторой параметр в функции (обратный вызов сбоя) выполняется, и сохраненное значение передается вthenВторая функция в качестве аргумента.

Promise.prototype.then = function (onResolved, onRejected) {
    let self = this;
    if (self.status === 'resolved'); {
        onResolved(self.success);           //将resolve函数保留的成功值传递作为参数
    }
    if (self.status === 'rejected') {
        onRejected(self.error);              //将reject函数保留的失败值传递作为参数
    }
}

В соответствии с приведенным выше примером, приведите егоthenиспользование

слишком далекоPromiseПростая структура была в основном завершена, простой тест

let promise = new Promise((resolve, reject) => {
    console.log('start');
    resolve('success data');
})

promise.then(res => {
    console.log("res", res);
}, err => {
    console.log("err", err);
})

Результаты теста

start
res success data

Вышеуказанные шаги просто реализуют синхронную обработку, а затем реализуют асинхронную обработку и реализуют несколько вызовов экземпляра.thenметод (не связанный)

потому чтоjsОн однопоточный.Простое понимание цикла событий на стороне браузера заключается в том, чтобы сначала выполнять синхронные задачи, а затем выполнять асинхронные задачи. Задачи синхронизации хранятся в стеке вызовов.Главный поток будет выполнять задачи синхронизации в первую очередь.Когда все задачи синхронизации в стеке вызовов выполнены и основной поток пуст, основной поток перейдет в очередь задач, чтобы проверить, есть ли прописаны асинхронные задачи, callback-функция, если есть, будет выполняться, если нет, то будет ждать. Асинхронные задачи в очереди задач далее делятся на микрозадачи и макрозадачи, обе из которых также имеют соответствующие последовательности выполнения. Подробности могут подождать в следующей статье

Ближе к дому, реализуйте асинхронную обработку и множественные вызовы

еслиPromiseОбработка является асинхронной функцией, тогда, когдаthenВ это время параметры в функции привода будут помещены в очередь асинхронных задач, то есть в это времяPromiseЭкземпляры по-прежнему находятся в состоянии по умолчаниюpending, нет изменений, то мы не знаем, что делать в это времяthenЕсли вы не знаете, какая функция обратного вызова будет выполнена, вам нужно сохранить эти две функции обратного вызова, дождаться подходящего времени, чтобы определить, какую функцию вызывать.

function Promise(executor) {
    let self = this; //保留this。防止后面方法出现this只想不明的问题
    self.status = 'pending'; //promise的默认状态是pending
    self.success = undefined; //保存成功回调传递的值
    self.error = undefined; //保存失败回调传递的值

    self.onSuccessCallbacks = []; //存放成功的回调
    self.onErrorCallbacks = []; //存放失败的回调

    function resolve(success) {
        if (self.status === 'pending') {
            self.status = 'resolved'; //成功函数将其状态修改为resolved
            self.success = success; //将成功的值保存起来
            self.onSuccessCallbacks.forEach(element => {
                element();
            });
        }
    }

    function reject(error) {
        if (self.status === 'pending') {
            self.status = 'rejected'; //失败函数将其函数修改为rejected
            self.error = error; //将失败的值保存起来
            self.onErrorCallbacks.forEach(element => {
                element();
            })
        }
    }
    executor(resolve, reject);
}


Promise.prototype.then = function (onResolved, onRejected) {
    let self = this;
    if (self.status === 'pending') {
        self.onSuccessCallbacks.push(() => {
            onResolved(self.success); //将resolve函数保留的成功值传递作为参数
        })
        self.onErrorCallbacks.push(() => {
            onRejected(self.error); //将reject函数保留的失败值传递作为参数
        })
    }
    if (self.status === 'resolved') {
        onResolved(self.success); //将resolve函数保留的成功值传递作为参数
    }
    if (self.status === 'rejected') {
        onRejected(self.error); //将reject函数保留的失败值传递作为参数
    }
}

прецедент

let promise = new Promise((resolve, reject) => {
    setTimeout(function () {
        resolve('success data')
    }, 2000)
})

promise.then(res => {
    console.log("success:", res);
}, err => {
    console.log("error:", err);
})
promise.then(res => {
    console.log("success:", res);
}, err => {
    console.log("error:", err);
})

Результат теста появится через 2 секунды

success: success data
success: success data

продолжайте попытки, если позволитеPromiseвыдать ошибку как обращаться

let promise = new Promise((resolve, reject) => {
    throw new error("一个错误");
})

promise.then(res => {
    console.log("success:", res);
}, err => {
    console.log("error:", err);
})

результат:

решать проблему

  try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }

попробуйте еще раз, чтобы увидеть результаты

Результат модификации непосредственноexecutorФункция обрабатывает исключения, а если возникает ошибка, напрямую входитrejectметод.

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

PromiseДля достижения цепных вызовов необходимо пройтиthenметод возвращает новыйPromise.

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

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

Далее пошаговый анализ (просто нужно улучшитьthenфункция)

thenвложенный в функциюnew Promise

Впоследствии в основномresolvePromiseфункция, даxВыносить суждения и предпринимать соответствующие действия:

На данный момент основные функции завершены, ниже приведены исходный код, примеры тестов и результаты.

Исходный код:

//Promise函数
function Promise(executor) {
    let self = this; //保留this。防止后面方法出现this只想不明的问题
    self.status = 'pending'; //promise的默认状态是pending
    self.success = undefined; //保存成功回调传递的值
    self.error = undefined; //保存失败回调传递的值

    self.onSuccessCallbacks = []; //存放成功的回调
    self.onErrorCallbacks = []; //存放失败的回调

    function resolve(success) {
        if (self.status === 'pending') {
            self.status = 'resolved'; //成功函数将其状态修改为resolved
            self.success = success; //将成功的值保存起来
            self.onSuccessCallbacks.forEach(element => {
                element();
            });
        }
    }

    function reject(error) {
        if (self.status === 'pending') {
            self.status = 'rejected'; //失败函数将其函数修改为rejected
            self.error = error; //将失败的值保存起来
            self.onErrorCallbacks.forEach(element => {
                element();
            })
        }
    }
    try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }
}

//then函数
Promise.prototype.then = function (onResolved, onRejected) {
    let self = this;
    let promiseAgain = new Promise((resolve, reject) => {
        if (self.status === 'pending') {
            self.onSuccessCallbacks.push(() => {
                let x = onResolved(self.success); //将resolve函数保留的成功值传递作为参数
                resolvePromise(promiseAgain, x, resolve, reject);
            })
            self.onErrorCallbacks.push(() => {
                let x = onRejected(self.error); //将reject函数保留的失败值传递作为参数
                resolvePromise(promiseAgain, x, resolve, reject);
            })
        }
        if (self.status === 'resolved') {
            let x = onResolved(self.success); //将resolve函数保留的成功值传递作为参数
            resolvePromise(promiseAgain, x, resolve, reject);
        }
        if (self.status === 'rejected') {
            let x = onRejected(self.error); //将reject函数保留的失败值传递作为参数
            resolvePromise(promiseAgain, x, resolve, reject);
        }
    })
    return promiseAgain;
}
//resolvePromise函数
function resolvePromise(promiseAgain, x, resolve, reject) {
    if (promiseAgain === x) {
        return reject(new TypeError("循环调用"));
    }
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then;
            if (typeof then === 'function') {
                then.call(x, (y) => {
                    resolvePromise(promiseAgain, y, resolve, reject);
                }, (e) => {
                    reject(e);
                })
            } else {
                resolve(x);
            }
        } catch (error) {
            reject(error);
        }
    } else {
        resolve(x);
    }
}

module.exports = Promise;

Пример теста:

let Promise = require('./Promise');


let promise = new Promise((resolve, reject) => {
    setTimeout(function () {
        resolve('success data')
    }, 2000)
})

promise.then(res => {
        console.log("第一次调用", res);
        return res;
    }, err => {
        console.log("error:", err);
    })
    .then(res => {
        console.log("第二次调用",res);
        return res
    }, err => {
        console.log("err", err);
    })
    .then(res => {
        console.log("第三次调用",res);
    }, err => {
        console.log("err", err);
    })

Результаты теста:

第一次调用 success data
第二次调用 success data
第三次调用 success data

использовалPromise, мы небрежно говоримPromiseэто асинхронная функция, на самом делеPromiseв экземпляре (newпроцесс) является синхронным, в то время какthenОбратные вызовы, зарегистрированные в, выполняются асинхронно.

let Promise = require('./Promise');


let promise = new Promise((resolve, reject) => {
    console.log("其次会被执行");
    resolve("success data");
})

promise.then(res => {
        console.log("第一次调用", res);
        // return res;
    }, err => {
        console.log("error:", err);
    })

console.log("首先会被执行");

Результаты:

其次会被执行
第一次调用 success data
首先会被执行

Окончательный код:

//Promise函数
function Promise(executor) {
    let self = this; //保留this。防止后面方法出现this只想不明的问题
    self.status = 'pending'; //promise的默认状态是pending
    self.success = undefined; //保存成功回调传递的值
    self.error = undefined; //保存失败回调传递的值

    self.onSuccessCallbacks = []; //存放成功的回调
    self.onErrorCallbacks = []; //存放失败的回调

    function resolve(success) {
        if (self.status === 'pending') {
            self.status = 'resolved'; //成功函数将其状态修改为resolved
            self.success = success; //将成功的值保存起来
            self.onSuccessCallbacks.forEach(element => {
                element();
            });
        }
    }

    function reject(error) {
        if (self.status === 'pending') {
            self.status = 'rejected'; //失败函数将其函数修改为rejected
            self.error = error; //将失败的值保存起来
            self.onErrorCallbacks.forEach(element => {
                element();
            })
        }
    }
    try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }
}

//then函数
Promise.prototype.then = function (onResolved, onRejected) {
    onResolved = typeof onResolved == 'function' ? onResolved : val => val;
    onRejected = typeof onRejected == 'function' ? onRejected : err => {
        throw err;
    }
    let self = this;
    let promiseAgain = new Promise((resolve, reject) => {
        if (self.status === 'pending') {
            self.onSuccessCallbacks.push(() => {
                try {
                    let x = onResolved(self.success); //将resolve函数保留的成功值传递作为参数
                    resolvePromise(promiseAgain, x, resolve, reject);
                } catch (e) {
                    reject(e)
                }
            })
            self.onErrorCallbacks.push(() => {
                try {
                    let x = onRejected(self.error); //将reject函数保留的失败值传递作为参数
                    resolvePromise(promiseAgain, x, resolve, reject);
                } catch (e) {
                    reject(e)
                }
            })
        }
        if (self.status === 'resolved') {
            try {
                let x = onResolved(self.success); //将resolve函数保留的成功值传递作为参数
                resolvePromise(promiseAgain, x, resolve, reject);
            } catch (e) {
                reject(e)
            }
        }
        if (self.status === 'rejected') {
            try {
                let x = onRejected(self.error); //将reject函数保留的失败值传递作为参数
                resolvePromise(promiseAgain, x, resolve, reject);
            } catch (e) {
                reject(e)
            }
        }
    })
    return promiseAgain;
}
//resolvePromise函数
function resolvePromise(promiseAgain, x, resolve, reject) {
    if (promiseAgain === x) {
        return reject(new TypeError("循环调用"));
    }
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then;
            if (typeof then === 'function') {
                then.call(x, (y) => {
                    resolvePromise(promiseAgain, y, resolve, reject);
                }, (e) => {
                    reject(e);
                })
            } else {
                resolve(x);
            }
        } catch (error) {
            reject(error);
        }
    } else {
        resolve(x);
    }
}

module.exports = Promise;

Пример теста:

let Promise = require('./Promise');


let promise = new Promise((resolve, reject) => {
    setTimeout(function () {
        resolve('success data')
    }, 0)
})

promise.then(res => {
        console.log("第一次调用", res);
        return res;
    }, err => {
        console.log("error:", err);
    })
    .then(res => {
        console.log("第二次调用",res);
        return res
    }, err => {
        console.log("err", err);
    })
    .then(res => {
        console.log("第三次调用",res);
    }, err => {
        console.log("err", err);
    })

console.log("首先会被执行");

Результаты теста:

首先会被执行
第一次调用 success data
第二次调用 success data
第三次调用 success data

Эта статья только для моего собственного пониманияPromiseПосле исходного кода я написал его со своим пониманием, надеюсь, эта статья может быть полезной.

Наконец, я рекомендую читателям понятьPromise, вы можете узнать о цикле событий браузера, который очень полезен для смешанныхsetTimeOut,PromiseПорядок вывода очень полезен, вот рекомендуемая статьяЦикл событий на стороне браузера, а затем я мог бы также написать статью о цикле событий браузера.