предисловие
Во время собеседования интервьюер часто просит вас выполнить обещание, если вы выполняете его по спецификации А+, оно может не закончиться, пока не стемнеет.
Когда дело доходит до промисов, основная функция, которая в первую очередь приходит на ум, — это асинхронные связанные вызовы.В этой статье вы реализуете обещание, которое можно асинхронно связать в цепочку с помощью 20 строк кода.
Реализация этого промиса не рассматривает никаких исключений, а рассматривает только кратчайший код, чтобы читатели могли понять основной принцип асинхронного цепного вызова.
код
Сначала дайте код, это действительно 20 строк.
function Promise(fn) {
this.cbs = [];
const resolve = (value) => {
setTimeout(() => {
this.data = value;
this.cbs.forEach((cb) => cb(value));
});
}
fn(resolve);
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data);
if (res instanceof Promise) {
res.then(resolve);
} else {
resolve(res);
}
});
});
};
Основной случай
new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
})
.then((res) => {
console.log(res);
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 500);
});
})
.then(console.log);
Эта статья будет посвящена этому основному случаю.Производительность этого кода выглядит следующим образом:
- Выход 1 через 500 мс
- Выход 2 через 500 мс
выполнить
Конструктор
Сначала давайте реализуем конструктор Promise
function Promise(fn) {
// Promise resolve时的回调函数集
this.cbs = [];
// 传递给Promise处理函数的resolve
// 这里直接往实例上挂个data
// 然后把onResolvedCallback数组里的函数依次执行一遍就可以
const resolve = (value) => {
// 注意promise的then函数需要异步执行
setTimeout(() => {
this.data = value;
this.cbs.forEach((cb) => cb(value));
});
}
// 执行用户传入的函数
// 并且把resolve方法交给用户执行
fn(resolve);
}
Ладно, вернемся и посмотрим на дело после того, как написали сюда
const fn = (resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
};
new Promise(fn);
отдельно,fn
Это функция, переданная пользователем, которая вызывается внутри.resolve
После функции будетpromise
на экземпляреcbs
Сделайте все это один раз.
Пока мы не знаемcbs
Откуда взялись функции в этом массиве, тогда читайте дальше.
then
Вот самая важная тогда реализация, от которой зависит цепочка:
Promise.prototype.then = function (onResolved) {
// 这里叫做promise2
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data);
if (res instanceof Promise) {
// resolve的权力被交给了user promise
res.then(resolve);
} else {
// 如果是普通值 就直接resolve
// 依次执行cbs里的函数 并且把值传递给cbs
resolve(res);
}
});
});
};
вернуться к делу
const fn = (resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
};
const promise1 = new Promise(fn);
promise1.then((res) => {
console.log(res);
// user promise
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 500);
});
});
Обратите внимание на название здесь:
-
мы кладем
new Promise
Возвращенный экземпляр называетсяpromise1
-
существует
Promise.prototype.then
В реализации мы создаем новый возврат обещания, назовем егоpromise2
-
Вызывается пользователем
then
метод, пользователь вручную создает обещание и возвращает его для выполнения асинхронных операций, вызывая егоuser promise
затем вthen
В реализации внутреннее this фактически указывает наpromise1
а такжеpromise2
входящийfn
функция выполняетthis.cbs.push()
, на самом деле кpromise1
изcbs
Функция помещается в массив, ожидая последующего выполнения.
Promise.prototype.then = function (onResolved) {
// 这里叫做promise2
return new Promise((resolve) => {
// 这里的this其实是promise1
this.cbs.push(() => {});
});
};
Затем сосредоточьтесь на этой функции нажатия, обратите внимание, что эта функция находится вpromise1
Он будет выполнен после его разрешения.
// promise2
return new Promise((resolve) => {
this.cbs.push(() => {
// onResolved就对应then传入的函数
const res = onResolved(this.data)
// 例子中的情况 用户自己返回了一个user promise
if (res instanceof Promise) {
// user promise的情况
// 用户会自己决定何时resolve promise2
// 只有promise2被resolve以后
// then下面的链式调用函数才会继续执行
res.then(resolve)
} else {
resolve(res)
}
})
})
Если метод onResolved, переданный пользователем, затем возвращаетuser promise
, то этоuser promise
куда пользователь пойдет сам в нужный моментresolve promise2
, то дальше сюдаres.then(resolve)
разрешение in будет выполнено:
if (res instanceof Promise) {
res.then(resolve)
}
Рассмотрим следующий пример:
new Promise((resolve) => {
setTimeout(() => {
// resolve1
resolve(1);
}, 500);
})
// then1
.then((res) => {
console.log(res);
// user promise
return new Promise((resolve) => {
setTimeout(() => {
// resolve2
resolve(2);
}, 500);
});
})
// then2
.then(console.log);
then1
Весь этот блок фактически возвращаетpromise2
,Такthen2
На самом деле, это по существуpromise2.then(console.log)
,
то естьthen2
Зарегистрированная функция обратного вызова фактически входит вpromise2
изcbs
В массиве обратного вызова, и поскольку мы только что знали,resolve2
После звонка,user promise
Будет вызван разрешениемpromise2
разрешиться, а затемpromise2
внутреннийcbs
Массивы запускаются последовательно.
Это позволяет пользователям писать собственныеresolve2
После казни,then2
Логика будет продолжать выполняться, то естьАсинхронные связанные вызовы.
Краткое содержание статьи
Эта статья — просто простая реализация обещания, которое можно вызывать асинхронно в цепочке, но настоящее обещание намного сложнее, чем оно, включая обработку различных исключений и пограничных случаев.
Спецификация обещания A+ по-прежнему достойна прочтения каждым квалифицированным фронтенд-разработчиком.
Надеюсь, эта статья поможет вам!