1. Что такое обещание? Для решения какой проблемы мы используем промисы?
Промисы — это решение для асинхронного программирования: Синтаксически обещание — это объект, от которого вы можете получить сообщение для асинхронной операции; в своем первоначальном смысле это обещание, которое обещает дать вам результат через некоторое время. Промис имеет три состояния:ожидание (состояние ожидания), выполнено (состояние успеха), отклонено (состояние отказа); как только состояние изменится, оно не изменится снова. После создания экземпляра промиса он выполняется немедленно.
Я считаю, что все часто пишут такой код:
// 当参数a大于10且参数fn2是一个方法时 执行fn2
function fn1(a, fn2) {
if (a > 10 && typeof fn2 == 'function') {
fn2()
}
}
fn1(11, function() {
console.log('this is a callback')
})
В это время наше обетование возникло и стало реальностью.
Промисы используются для решения двух проблем:
- Ад обратного вызова, код сложно поддерживать, часто вывод первой функции является вводом второй функции
- Promise может поддерживать несколько одновременных запросов и получать данные из одновременных запросов.
- Этот промис может решить проблему асинхронности, нельзя сказать, что промис асинхронный.
Во-вторых, использование обещания es6
Promise — это конструктор, у него есть знакомые методы, такие как all, reject и resolve on the own, а также знакомые методы, такие как then и catch на основе его прототипа.
потом новый
let p = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('执行完成');
resolve('我是成功!!');
}, 2000);
});
- resolve : функция обратного вызова после успешного выполнения асинхронной операции.
- reject: функция обратного вызова после сбоя выполнения асинхронной операции
Использование операции then chain
p.then((data) => {
console.log(data);
})
.then((data) => {
console.log(data);
})
.then((data) => {
console.log(data);
});
Использование отклонения:
Установите состояние промиса на отклоненное, чтобы мы могли поймать его в then и выполнить обратный вызов для условия «сбой». См. код ниже.
let p = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num);
}
else{
reject('数字太大了');
}
}, 2000);
});
p.then((data) => {
console.log('resolved',data);
},(err) => {
console.log('rejected',err);
}
);
Использование улова
p.then((data) => {
console.log('resolved',data);
}).catch((err) => {
console.log('rejected',err);
});
Эффект такой же, как написано во втором параметре then. Но у него есть другая функция: при выполнении callback’а resolve (то есть первый параметр в потом выше), если будет выброшено исключение (код неверный), то он не сообщит об ошибке и не заблокирует js, а войдет в метод ловли. См. код ниже:
p.then((data) => {
console.log('resolved',data);
console.log(somedata); //此处的somedata未定义
})
.catch((err) => {
console.log('rejected',err);
});
Использование всех: тот, кто работает медленнее, выполнит обратный вызов. all получает параметр массива, а значения в нем в итоге вернутся в объект Promise
let Promise1 = new Promise(function(resolve, reject){})
let Promise2 = new Promise(function(resolve, reject){})
let Promise3 = new Promise(function(resolve, reject){})
let p = Promise.all([Promise1, Promise2, Promise3])
p.then(funciton(){
// 三个都成功则成功
}, function(){
// 只要有失败,则失败
})
При всем этом вы можете выполнять несколько асинхронных операций параллельно и обрабатывать все возвращаемые данные в одном обратном вызове, разве это не круто?Есть сцена, которая очень подходит для использования этого.Для некоторых приложений с большим количеством игровых материалов, при открытии веб-страницы, предзагружаются различные ресурсы, такие как картинки, flash и различные статические файлы. После того, как все загружено, приступаем к инициализации страницы.
Использование гонки: тот, кто бежит быстрее, выполнит обратный вызов
//请求某个图片资源
function requestImg(){
var p = new Promise((resolve, reject) => {
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = '图片的路径';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise.race([requestImg(), timeout()]).then((data) =>{
console.log(data);
}).catch((err) => {
console.log(err);
});
Ну, я думаю, что все уже поняли использование, так что давайте напишем собственное обещание.
3. Реализуйте собственное обещание на основе обещания+
Шаг 1: Реализуйте методы обратного вызова для успеха и неудачи
Для достижения функции в приведенном выше коде это также самая основная функция обещания. Во-первых, вам нужно создать обещание конструктора, создать класс обещания и передать исполнителю при его использовании.Исполнитель будет передавать два параметра: успех (разрешение) и отказ (отказ). Как я уже говорил, пока вы преуспеете, вы не потерпите неудачу, а пока вы потерпите неудачу, вы не добьетесь успеха. Поэтому по умолчанию при успешном вызове возвращается состояние успеха, а при неудачном вызове возвращается состояние отказа. код показывает, как показано ниже:
class Promise {
constructor (executor){
//默认状态是等待状态
this.status = 'panding';
this.value = undefined;
this.reason = undefined;
//存放成功的回调
this.onResolvedCallbacks = [];
//存放失败的回调
this.onRejectedCallbacks = [];
let resolve = (data) => {//this指的是实例
if(this.status === 'pending'){
this.value = data;
this.status = "resolved";
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === 'pending'){
this.reason = reason;
this.status = 'rejected';
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{//执行时可能会发生异常
executor(resolve,reject);
}catch (e){
reject(e);//promise失败了
}
}
Спецификация обещания A+ предусматривает, что при возникновении нештатной ошибки выполняется функция отказа.
constructor (executor){
...... try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
Шаг 2: затем вызов цепочки методов
Метод then — это самый простой метод обещания. Он возвращает два обратных вызова, успешный обратный вызов и неудачный обратный вызов. Процесс реализации выглядит следующим образом:
then(onFulFilled, onRejected) {
if (this.status === 'resolved') { //成功状态的回调
onFulFilled(this.value);
}
if (this.status === 'rejected') {//失败状态的回调
onRejected(this.reason);
}
}
let p = new Promise(function(){
resolve('我是成功');
})
p.then((data) => {console.log(data);},(err) => {});
p.then((data) => {console.log(data);},(err) => {});
p.then((data) => {console.log(data);},(err) => {});
Возвращаемый результат:
我是成功
我是成功
我是成功
then(onFulFilled, onRejected) {
if (this.status === 'resolved') {
onFulFilled(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
// 当前既没有完成 也没有失败
if (this.status === 'pending') {
// 存放成功的回调
this.onResolvedCallbacks.push(() => {
onFulFilled(this.value);
});
// 存放失败的回调
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
}
}
Спецификация Promise A+ предусматривает, что метод then может вызываться в цепочке
В обещаниях результатом цепного вызова является возврат нового обещания.Результат, возвращенный в первом then, независимо от того, успешно оно или нет, будет возвращен в состояние успеха в следующем then, а в первом then Если возникло исключение возникает ошибка, затем она вернется в состояние сбоя в следующем, а затем
Когда цепочка вызовов успешна
function resolvePromise(p2,x,resolve,reject){
....
}
- Возвращаемый результат не может быть самим собой
var p = new Promise((resovle,reject) => {
return p; //返回的结果不能是自己,
})
Никогда не преуспевать и не терпеть неудачу, если возвращаемый результат равен self, поэтому при возврате self должна быть выдана ошибка.
function resolvePromise(p2,x,resolve,reject){
if(px===x){
return reject(new TypeError('自己引用自己了'));
}
....
}
- Результат возврата может быть обещанием
function resolvePromise(promise2,x,resolve,reject){
//判断x是不是promise
//规范中规定:我们允许别人乱写,这个代码可以实现我们的promise和别人的promise 进行交互
if(promise2 === x){//不能自己等待自己完成
return reject(new TypeError('循环引用'));
};
// x是除了null以外的对象或者函数
if(x !=null && (typeof x === 'object' || typeof x === 'function')){
let called;//防止成功后调用失败
try{//防止取then是出现异常 object.defineProperty
let then = x.then;//取x的then方法 {then:{}}
if(typeof then === 'function'){//如果then是函数就认为他是promise
//call第一个参数是this,后面的是成功的回调和失败的回调
then.call(x,y => {//如果Y是promise就继续递归promise
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},r => { //只要失败了就失败了
if(called) return;
called = true;
reject(r);
});
}else{//then是一个普通对象,就直接成功即可
resolve(x);
}
}catch (e){
if(called) return;
called = true;
reject(e)
}
}else{//x = 123 x就是一个普通值 作为下个then成功的参数
resolve(x)
}
}
- Возвращенный результат может быть обычным значением, тогда сразу разрешается (x);
- Промисы можно вызывать только в случае успеха или неудачи
То есть, когда вызов успешен, вызов больше не может потерпеть неудачу.Если оба вызываются, будет выполнено то, что было вызвано первым. Часть кода такая же, как и выше
Лично я считаю, что это место достаточно извилистое, и его нужно разъяснять поэтапно не спеша.
Согласно принципу спецификации promise A+, promise инкапсулирует ряд встроенных методов в свою собственную структуру.
- Способы отлова ошибокcatch()
- Разобрать все методыall()
- соревнованиеrace()
- Создайте успешное обещаниеresolve()
- создать невыполненное обещаниеreject()
Наконец, я прилагаю весь исходный код для внимательного прочтения всеми.
function resolvePromise(promise2,x,resolve,reject){
//判断x是不是promise
//规范中规定:我们允许别人乱写,这个代码可以实现我们的promise和别人的promise 进行交互
if(promise2 === x){//不能自己等待自己完成
return reject(new TypeError('循环引用'));
};
// x是除了null以外的对象或者函数
if(x !=null && (typeof x === 'object' || typeof x === 'function')){
let called;//防止成功后调用失败
try{//防止取then是出现异常 object.defineProperty
let then = x.then;//取x的then方法 {then:{}}
if(typeof then === 'function'){//如果then是函数就认为他是promise
//call第一个参数是this,后面的是成功的回调和失败的回调
then.call(x,y => {//如果Y是promise就继续递归promise
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},r => { //只要失败了就失败了
if(called) return;
called = true;
reject(r);
});
}else{//then是一个普通对象,就直接成功即可
resolve(x);
}
}catch (e){
if(called) return;
called = true;
reject(e)
}
}else{//x = 123 x就是一个普通值 作为下个then成功的参数
resolve(x)
}
}
class Promise {
constructor (executor){
//默认状态是等待状态
this.status = 'panding';
this.value = undefined;
this.reason = undefined;
//存放成功的回调
this.onResolvedCallbacks = [];
//存放失败的回调
this.onRejectedCallbacks = [];
let resolve = (data) => {//this指的是实例
if(this.status === 'pending'){
this.value = data;
this.status = "resolved";
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === 'pending'){
this.reason = reason;
this.status = 'rejected';
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{//执行时可能会发生异常
executor(resolve,reject);
}catch (e){
reject(e);//promise失败了
}
}
then(onFuiFilled,onRejected){
//防止值得穿透
onFuiFilled = typeof onFuiFilled === 'function' ? onFuiFilled : y => y;
onRejected = typeof onRejected === 'function' ? onRejected :err => {throw err;}
let promise2;//作为下一次then方法的promise
if(this.status === 'resolved'){
promise2 = new Promise((resolve,reject) => {
setTimeout(() => {
try{
//成功的逻辑 失败的逻辑
let x = onFuiFilled(this.value);
//看x是不是promise 如果是promise取他的结果 作为promise2成功的的结果
//如果返回一个普通值,作为promise2成功的结果
//resolvePromise可以解析x和promise2之间的关系
//在resolvePromise中传入四个参数,第一个是返回的promise,第二个是返回的结果,第三个和第四个分别是resolve()和reject()的方法。
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e);
}
},0)
});
}
if(this.status === 'rejected'){
promise2 = new Promise((resolve,reject) => {
setTimeout(() => {
try{
let x = onRejected(this.reason);
//在resolvePromise中传入四个参数,第一个是返回的promise,第二个是返回的结果,第三个和第四个分别是resolve()和reject()的方法。
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e);
}
},0)
});
}
//当前既没有完成也没有失败
if(this.status === 'pending'){
promise2 = new Promise((resolve,reject) => {
//把成功的函数一个个存放到成功回调函数数组中
this.onResolvedCallbacks.push( () =>{
setTimeout(() => {
try{
let x = onFuiFilled(this.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},0)
});
//把失败的函数一个个存放到失败回调函数数组中
this.onRejectedCallbacks.push( ()=>{
setTimeout(() => {
try{
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
})
})
}
return promise2;//调用then后返回一个新的promise
}
catch (onRejected) {
// catch 方法就是then方法没有成功的简写
return this.then(null, onRejected);
}
}
Promise.all = function (promises) {
//promises是一个promise的数组
return new Promise(function (resolve, reject) {
let arr = []; //arr是最终返回值的结果
let i = 0; // 表示成功了多少次
function processData(index, data) {
arr[index] = data;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (data) {
processData(i, data)
}, reject)
}
})
}
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
// 生成一个成功的promise
Promise.resolve = function(value){
return new Promise((resolve,reject) => resolve(value);
}
// 生成一个失败的promise
Promise.reject = function(reason){
return new Promise((resolve,reject) => reject(reason));
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise( (resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}
module.exports = Promise;
Что касается резюме этой спецификации обещания A +, определенно будет много недостатков.Вы можете высказать ценные мнения или предложения, и я надеюсь помочь вам получить некоторые знания из этого!