предисловие: Прежде чем изучать async/awit, нам необходимо изучить,итератора такжеГенератор
Итераторы и генераторы
предисловие: при переборе данных с оператором цикла необходимо инициализировать соответствующие переменные для записи положения каждой итерации в наборе данных.
Использование итераторов может значительно упростить манипулирование данными, поэтому ES6 также добавил эту функцию итератора в js. Новые методы массивов и новые типы коллекций (например, коллекции Set и Map) зависят от реализации итераторов, а итераторы можно использовать даже в асинхронном программировании.
Но перед этим мы должны понять итератористория позади.
проблема оператора цикла
var colors = ['red','green','blue'];
for(var i = 0 ,len = colors.length ; i < len ; i ++) {
console.log(colors[i])
}
Выше приведен стандартный код цикла, который отслеживает индекс массива цветов через переменную i.
Хотя синтаксис оператора цикла прост, если несколько циклов вложены друг в друга, необходимо отслеживать несколько переменных, что значительно увеличивает сложность кода. Итераторы были созданы, чтобы устранить эту сложность и уменьшить количество ошибок в циклах.
что такое итератор
Итератор — это специальный объект, который имеет некоторые проприетарные интерфейсы, разработанные для процесса итерации.Все объекты итераторов имеют метод next(), который возвращает объект результата при каждом вызове. Объект результата имеет два свойства: одно — это значение, представляющее следующее возвращаемое значение; другое — выполнено, представляющее собой логическое значение, которое возвращает значение true, когда больше нет данных для возврата. Итератор также содержит внутренний указатель на положение значения в текущей коллекции, и каждый раз, когда вызывается метод next(), возвращается следующее доступное значение.
Мы используем синтаксис es5, чтобы написать итератор самостоятельно.
Насколько я понимаю, это должно относиться к полезности замыканий
function createIterator(items) {
var i = 0;
return {
next :function() {
var done = ( i >= items.length);
var value = !done ? items[i++] :undefined;
return {
done : done,
value : value
}
}
}
}
var iterator = createIterator([1,2,3]);
console.log(iterator.next()) //{ done: false, value: 1 }
console.log(iterator.next()) //{ done: false, value: 2 }
console.log(iterator.next()) //{ done: false, value: 3 }
console.log(iterator.next()) //{ done: true, value: undefined }
console.log(iterator.next()) //{ done: true, value: undefined }
Правила написания итераторов столь же сложны, но ES6 также вводит объект-генератор, который упрощает процесс создания объектов-итераторов.
note: Проверить, является ли объект итерируемым
function isIterable(object) {
return typeof object[Symbol.iterator] === "function";
}
что такое генератор
Генератор — это функция, которая возвращает итератор, обозначенный звездочкой (*) после ключевого слова function, и в функции используется новое ключевое слово yield. так :
//生成器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 生成器的调用方式与普通函数相同, 只不过返回的是一个迭代器
let iterator = createIterator();
console.log(iterator.next())//{ value: 1, done: false }
console.log(iterator.next())//{ value: 2, done: false }
console.log(iterator.next())//{ value: 3, done: false }
console.log(iterator.next())//{ value: undefined, done: true }
В этом примере звездочка перед createIterator() указывает на то, что это генератор; ключевое слово yield также является новой функцией es6, которую можно использовать для указания возвращаемого значения и порядка возврата при вызове метода next() итератора. После создания итератора вызов его метода next() три раза подряд возвращает три разных значения, а именно 1, 2 и 3. Процесс вызова генератора такой же, как и у других функций, а конечным результатом является созданный итератор.
Самое главное в функции генератора,Функция автоматически прекратит выполнение после выполнения каждого оператора yield..
Асинхронное выполнение задачи
Большинство интересных функций генераторов связаны с асинхронным программированием.Асинхронное программирование в JavaScript имеет свои преимущества и недостатки: асинхронизация простых задач достигается очень легко, асинхронизация сложных задач создает много проблем в управлении кодом. Поскольку генераторы поддерживают приостановку выполнения кода внутри функций, можно глубже изучить другие варианты использования асинхронной обработки. Все становится очень сложно, если вложенные обратные вызовы необходимы для сериализации серии асинхронных операций. Здесь пригодятся генераторы и операторы yield.
простой исполнитель задач
Потому что выполнение оператора yield приостановит выполнение текущей функции и будет ждать следующего вызова метода next(). Таким образом, вы можете создать функцию и вызвать генератор в функции для создания соответствующего итератора, чтобы вы могли асинхронно вызывать метод next() без функции обратного вызова, например:
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
// 开始执行任务
let result = task.next();
//循环调用next()的函数
function step() {
// 如果任务未完成,则继续执行
if(!result.done) {
result = task.next();
step();
}
}
//开始迭代执行
step();
}
// 执行
run(function *() {
console.log(1);
yield;
console.log(2);
yield;
console.log(3)
})
Функция run() получает в качестве параметра функцию-генератор, эта функция определяет задачу, которая будет выполняться впоследствии, генерирует итератор и сохраняет его в переменной task. Когда метод итератора next() вызывается в первый раз, возвращенный результат сохраняется для последующего использования. Функция step() проверяет значение result.done и, если оно ложно, выполняет метод next() итератора и снова выполняет операцию step(). Каждый раз, когда вызывается метод next(), самая последняя возвращаемая информация всегда перезаписывает результат переменной. В конце кода инициализируйте выполнение функции step() и запустите весь итеративный процесс, каждый раз проверяя result.done, чтобы определить, есть ли еще задачи для выполнения.
Передать данные исполнителю задачи
Самый простой способ передать данные исполнителю задачи — передать значение через метод итератора next() в качестве сгенерированного yield значения для следующего вызова. В следующем коде вам нужно только передать result.value в метод next():
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
//开始执行任务
let result = task.next();
// 循环调用next()的函数
function step() {
//如果任务未完成 , 则继续执行
if(!result.done) {
result = task.next(result.value);
step();
}
}
//开始迭代执行
step();
}
run(function *() {
let value = yield 1;
console.log(value); // 1
value = yield value + 3;
console.log(value);
})
В этом примере на консоль выводятся два числа 1 и 4.
Теперь, когда данные могут передаваться между вызовами yield, требуется лишь небольшое изменение для поддержки асинхронных вызовов.
асинхронный исполнитель задач
В предыдущем примере статические данные просто передавались туда и обратно между несколькими вызовами yield, а ожидание асинхронного процесса немного отличается. Исполнитель задачи должен знать, что такое функция обратного вызова и как ее использовать. Поскольку выражение yield возвращает значение исполнителю задачи, все вызовы функций возвращают значение, так что это также в некотором роде асинхронная операция, и исполнитель задачи будет ждать завершения операции.
Ниже мы определяем асинхронную операцию:
function fetchData() {
return function(callback) {
setTimeout(function() {
callback(null,'Hi');
}, 50)
}
}
Теперь, когда мы понимаем, как асинхронные процессы работают в функциях, мы можем немного изменить исполнителя задачи. Когда result.value является функцией, исполнитель задачи сначала выполнит функцию, а затем передаст результат методу next() Код обновляется следующим образом:
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
//开始执行任务
let result = task.next();
// 循环调用next()函数
function step() {
//如果任务未完成 , 则继续执行
if(!result.done) {
if(typeof result.value === "function") {
result.value(function(err,data) {
if(err) {
result = task.throw(err);
return;
}
result = task.next(data);
step();
});
} else {
result = task.next(result.value);
step();
}
}
}
//开始执行迭代
step();
}
После проверки оператором ===, если result.value является функцией, функция обратного вызова будет передана в качестве параметра для ее вызова.Функция обратного вызова соответствует соглашению об ошибках выполнения в node.js; возможные ошибки помещаются первыми параметр (err), результат помещается во второй параметр. Если передается err, это означает, что во время выполнения генерируется cuow, и объект ошибки будет корректно выводиться через task.throw(). Если result.value не является функцией, передайте его непосредственно методу next().
Теперь эту новую версию выполнения задачи можно использовать уже для всех асинхронных задач. В среде node.js, если вы читаете какие-то данные из файла, вам нужно создать обёртку (wrapper) в периферии fs.readFile(), возврат аналогичный функции fetchData()
let fs = require('fs');
function readFile(filename) {
return function(callback) {
fs.readFile(filename,'utf8',callback);
}
}
//调用
run(function *(){
let contents = yield readFile('1.txt');
console.log(contents);
})
Обещания и асинхронное программирование
Эй, мы наконец-то начинаем учить Обещания, а потом научимся
- В чем причина обещаний
- что такое обещание
- Основные концепции промисов
- Наконец, мы вручную напишем простое обещание
Фон асинхронного программирования
Движок javaScript построен на концепции одного потока и цикла событий, что позволяет одновременно выполнять только один блок кода.
Причины обещаний
А что, если однажды нам придется управлять порядком выполнения двух асинхронных операций?
Например, мы должны сначала прочитать файл 1.txt, а затем сделать копию файла 2.txt.
Мы знаем, что операции ввода-вывода асинхронны, поэтому для управления порядком можно сделать так:
fs.readFile('./1.txt','utf8',(err,data)=>{
fs.writeFile('./2.txt',data,(err)=>{
if(err) {
return;
}
})
})
Проще говоря, это выполнение операции записи в режиме чтения. Но это не очень хорошо, потому что как только код для работы с асинхронной последовательностью увеличивается,Как только вы не знаете, где ошибка, ее будет сложно отлаживать, и голова будет большой.
что такое обещание
Promise — это решение для асинхронных операций, которое выражает сложные традиционные функции обратного вызова и асинхронные операции, которые прослушивают события в виде синхронного кода. Это позволяет избежать вложенности функций обратного вызова для многоуровневых асинхронных операций.
Основные концепции промисов
Обещание эквивалентно заполнителю для результата асинхронной операции.Он не будет подписываться на событие и не будет передавать функцию обратного вызова целевой функции, но позволяет функции возвращать обещание.
Жизненный цикл обещания
Каждый промис будет проходить короткий жизненный цикл: сначала он находится в состоянии ожидания, и операция в это время не завершена, поэтому он также не выполнен; после завершения асинхронной операции промис становится следующим Единицей:
- Асинхронная операция Fulfilled Promise успешно завершена
- Отклонено. Не удалось успешно завершить асинхронную операцию Promise из-за ошибки программы или по какой-либо другой причине.
note:Если объект реализует метод then(), то этот объект называется объектом с поддержкой then. Все промисы являются объектами, доступными для обработки, но не все объекты, которые могут быть обработаны, являются промисами.
С помощью Promise мы можем превратить описанные выше операции чтения и записи в следующие:
//读
function readPath(path) {
return new Promise((resolve,reject)=>{
fs.readFile(path,'utf8',(error,data)=>{
if(error) {
reject(error);
} else {
resolve(data)
}
})
})
}
//写
function wirtePath(path,data) {
return new Promise((resolve,reject)=>{
fs.writeFile(path,data,(error)=>{
if(error) {
reject(error)
} else {
resolve('success')
}
})
})
}
readPath('./1.txt')
.then((data)=>{
wirtePath('./2.txt',data);
},(reason)=>{
console.log(reason);
})
Лучшее асинхронное выполнение задач:Его основная идея заключается в
Используйте асинхронные помеченные функции вместо генераторов и ожидайте вместо функции yield to call.,так
async function (){
let content = await readPath('./1.txt');
let msg = await wirtePath('./2.txt',content);
console.log(msg)
}() // 这里是自执行函数
Рукописное обещание
Мы чувствуем, что вместо того, чтобы смотреть на все виды на обещанных вопросов интервью, лучше реализовать обещание сначала. После понимания принципа, естественно легче знать, как его использовать. Теперь, давайте начнем финальный код этой статьи,Реализовать простое обещание,
Заявление об обещаниях
Прежде всего, Promise должен быть классом, мы используем class для объявления
-
Поскольку new Promise((resolve,reject) => {}), входящий параметр является функцией, мы называем его executor и выполняем, когда он передается в
-
В исполнителе есть два параметра, один называется resolve (успех), а другой называется reject (отказ).
-
Поскольку resolve и reject являются исполняемыми, все они являются функциями, и мы объявляем их с помощью let
class Promise { constructor(executor) { // 成功 let resolve = (value) => {}; // 失败 let reject = (reason) => {}; } }
Решить базовое состояние
Правила обещаний
-
Обещание имеет три состояния (состояние) ожидание, выполнено, отклонено
-
ожидание (состояние ожидания) является начальным состоянием и может быть преобразовано в выполненное (состояние успеха) и отклоненное (состояние отказа)
-
В случае успеха его нельзя изменить на другое состояние, и оно должно иметь неизменяемое значение (value)
-
При неудаче его нельзя изменить на другое состояние, и должна быть неизменная причина (причина)
-
новое обещание ((разрешить, отклонить) => {разрешить (значение)}) разрешение выполнено успешно, параметр приема, значение, состояние изменено на Выполнено, повторно изменить нельзя.
-
new Promise((resolve, reject)=>{reject(reason)}) Reject — сбой, получен параметр Reason и состояние изменено на reject, которое нельзя изменить повторно.
-
Если функция-исполнитель сообщает об ошибке, вызовите функцию reject() напрямую;
class Promise { constructor(executor) { //初始化 state 为等待状态 this.state = 'pending'; // 成功的值 this.value = undefined; // 失败的值 this.reason = undefined; let resolve = (value) => { // state 改变 , resolve 调用会失败 if(this.state === 'pending') { this.state = 'fulfilled';// 调用 resolve后,state转化为成功状态 this.value = value;// 存储成功的值 } }; // 失败 let reject = (reason) => { //state 改变后, reject 调用就会失败 if(this.state === 'pending') { // reject 调用后, state 转化为失败状态 this.state = 'rejected'; this.reason = reason;// 存储失败的原因 } }; // 立即执行 // 如果 executor 执行报错 , 直接执行 reject try { executor(resolve,reject); } catch (err) { reject(err); } } }
затем метод
Положения: у обещания есть метод, вызываемый then, который имеет два параметра: onFulfilled, onRejected, успех имеет значение успеха, сбой имеет причину сбоя
-
Когда состояние состояния выполнено, выполнить onFulfilled, передать this.value Когда состояние состояния отклонено, выполнить onRejected, передать this.reason
-
onFulfilled, onRejected Если это функции, они должны быть вызваны после выполнения, соответственно отклонения, со значением или причиной в качестве их первого параметра по очереди.
then(onFulfilled,onRejected) { // 状态为 fulfilled , 执行 onFulfilled , 传入成功的值 if(this.state === 'fulfilled') { onFulfilled(this.value); }; // 状态为rejected , 执行onRejected , 传入失败的原因 if(this.state === 'rejected') { onRejected(this.reason); } }
Решить асинхронную проблему
Теперь мы можем в основном реализовать простой синхронный код, но когда разрешение выполняется в пределах setTimeout, а затем состояние все еще находится в ожидании, нам нужно сохранить успех и отказ в соответствующих массивах, когда затем вызывается. Подобно публикации и подписке, сначала сохраните две функции в then.Поскольку промис может иметь несколько then, они существуют в одном и том же массиве.
// 手写Promise
class Promise {
constructor(executor) {
//初始化状态
this.state = 'pending';
// 成功值
this.value = undefined;
// 失败值
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放的数组
this.onRejectedCallbacks = [];
// 成功
let resolve = (value) => {
// state 改变 , resolve 调用
if(this.state === 'pending') {
this.state = 'fulfilled';// 调用 resolve 后 , state转换为成功状态
this.value = value;//存储成功的值
// 一旦resolve 执行, 调用成功数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失败
let reject = (reason) => {
if(this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦 resolve执行 , 调用失败数组的函数
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve,reject);
} catch (error) {
reject(error)
}
}
then(onFulfilled,onRejected) {
// 状态为 fulfilled , 执行 onFulfiiled , 传入成功的值
if(this.state === 'fulfilled') {
onFulfilled(this.value);
};
//状态为 rejected , 执行onRejected , 传入失败的原因
if(this.state === 'rejected') {
onRejected(this.reason);
}
// 当状态为 pending时
if(this.state === 'pending') {
// onFulfilled 传入到成功数组中
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected 传入到失败数组
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
catch() {
}
}
Разрешение связанных вызовов
我们常常用到的 new Promise().then().then(),这就是链式调用,用来解决回调地狱的问题。
- Чтобы достичь цепочки, мы по умолчанию возвращаем промис первым.
Условие: вернуть новое обещание в then с именем promise2;
promise2 = new Promise((resolve,reject)=>{})
- Передайте значение, возвращаемое этим promise2, следующему, а затем
- Если возвращается нормальное значение, передайте нормальное значение следующему, а затем
- Когда мы возвращаем параметр в первый then (параметр неизвестен и его нужно оценить). Новое обещание, возвращаемое этим, является значением onFulfilled() или onRejected(). Условие: значение onFulfilled() или onRejected(), то есть значение, возвращаемое первым then, называется x, а функция, оценивающая x, называется resolvePromise.
-
Во-первых, посмотрите, является ли x обещанием
-
Если это обещание, примите его результат как новое обещание2.
-
Если это нормальное значение, оно напрямую используется как результат успеха promise2.
-
Итак, чтобы сравнить x с обещанием2
-
Параметры resolvePromise: promise2 (возвращенное обещание по умолчанию), x (объект, который мы возвращаем сами), resolve, reject
-
разрешить и отклонить обещание2
class Promise { constructor(executor) { //初始化状态 this.state = 'pending'; // 成功值 this.value = undefined; // 失败值 this.reason = undefined; // 成功存放的数组 this.onResolvedCallbacks = []; // 失败存放的数组 this.onRejectedCallbacks = []; // 成功 let resolve = (value) => { // state 改变 , resolve 调用 if (this.state === 'pending') { this.state = 'fulfilled';// 调用 resolve 后 , state转换为成功状态 this.value = value;//存储成功的值 // 一旦resolve 执行, 调用成功数组的函数 this.onResolvedCallbacks.forEach(fn => fn()); } } // 失败 let reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; // 一旦 resolve执行 , 调用失败数组的函数 this.onRejectedCallbacks.forEach(fn => fn()); } } try { executor(resolve, reject); } catch (error) { reject(error) } } then(onFulfilled, onRejected) { // 声明返回的 promise2 let promise2 = new Promise((resolve, reject) => { // 状态为 fulfilled , 执行 onFulfiiled , 传入成功的值 if (this.state === 'fulfilled') { let x = onFulfilled(this.value); // resolvePromise 函数 , 处理自己 return 的 promise和 默认的 promise2的关系 resolvePromise(promise2, x, resolve, reject); }; //状态为 rejected , 执行onRejected , 传入失败的原因 if (this.state === 'rejected') { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } // 当状态为 pending时 if (this.state === 'pending') { // onFulfilled 传入到成功数组中 this.onResolvedCallbacks.push(() => { let x = onFulfilled(this.value); resolvePromise(promise2,x,resolve,reject); }) // onRejected 传入到失败数组 this.onRejectedCallbacks.push(() => { let x = onRejected(this.reason); resolvePromise(promise2,x,resolve,reject); }) } }); // 返回promise2 , 完成链式 return promise2; } }
Завершите функцию resolvePromise
Provisions: фрагмент кода, который позволяет применять разные коды промисов друг к другу, называемый resolvePromise.
-
Если x === promise2 , это вызовет циклическую ссылку, и если вы дождетесь завершения, будет сообщено об ошибке «циклическая ссылка».
function resolvePromise(promise2,x,resolve,reject) { if(x === promise2) { return reject(new TypeError('Chaining cycle detected for promise')); } }
- судья х
- Если x является объектом или функцией, установите значение x
- х не может быть нулевым
- x - нормальное значение, затем сразу разрешите (x)
- x — объект или функция (включая промисы), let then = x.then;
- объявил тогда
- Если вы берете then и сообщаете об ошибке, то переходите к reject()
- Если then это функция, используйте вызов для выполнения then, первым параметром будет this, за которым следует успешный обратный вызов и неудачный обратный вызов
- Если это успешный обратный вызов или обещание, продолжайте рекурсию
- Только один вызов может быть выполнен для успеха и неудачи, поэтому установите вызов, чтобы предотвратить несколько вызовов.
примечание: этот метод является сутью исходного кода Promise, вы можете посмотреть поближе
// 完成 resolvePromise函数
function resolvePromise(promise2, x, resolve, reject) {
// 循环引用报错
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
//防止多次调用
let called;
// x不是null 并且 x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定 , 声明 then = x 的 then 方法
let then = x.then;
//如果 then 是函数 , 就默认是promise 了
if (typeof then === 'function') {
// 就让 then 执行 第一个参数是 this 后面是成功的回调 和失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve 就结果依旧是 promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if(called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
другие проблемы
- Требования: onFulfilled, onRejected — необязательные параметры, если они не функции, их нужно игнорировать
- onFulfilled возвращает обычное значение, которое в случае успеха равно значению value => value.
- onRejected возвращает нормальное значение.Если он терпит неудачу, если он прямо равен value => value, он перейдет к onFulfilled в следующем then, поэтому сразу выдается ошибка err => throw err
- Указывает, что onFulfilled или onRejected не могут вызываться синхронно и должны вызываться асинхронно. Мы используем setTimeout для решения асинхронной проблемы
- Если onFulfilled или onRejected сообщает об ошибке, то напрямую возвращайте reject()
Окончательный версия
можно посмотреть посмотреть
// 手写Promise
class Promise {
constructor(executor) {
// 初始化state 为等待状态
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的值
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放的数组
this.onRejectedCallbacks = [];
// 成功
let resolve = (value) => {
// state 改变 , resolve 调用的会失败
if (this.state === 'pending') {
this.state = 'fulfilled'; // resolve调用后 , state转化为成功态
this.value = value;// 存储成功的值
// 一旦resolve执行 , 调用成功数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失败
let reject = (reason) => {
// state改变后 , reject调用就会失败
if (this.state === 'pending') {
// reject 调用后 , state 转换为失败状态
this.state = 'rejected';
this.reason = reason;// 存储失败的原因
// 一旦reject 执行 , 调用失败数组的函数
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 立即执行
// 如果 executor 执行报错 , 直接执行 reject
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// onFulfilled 如果不是函数 , 就忽略 onFulfilled , 直接返回 value
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
// onRejected 如果不是函数 , 就忽略 onRejected , 直接扔出错误
onRejected = typeof onRejected === "function" ? onRejected : err => { throw err };
// 声明返回的 promise2
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// resolvePromise函数 , 处理自己return 的promise和默认的promise2的关系
resolvePromise(promise2, x ,resolve,reject);
} catch (e) {
reject(e);
}
},0)
};
if (this.state === 'rejected') {
//异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0);
};
// 当状态state为pending 时
if (this.state === 'pending') {
// onFulfilled传入到成功数组
this.onResolvedCallbacks.push(() => {
//异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2,x , resolve,reject);
} catch (e) {
reject(e)
}
},0);
})
// onRejected 传入到失败数组
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e)
}
})
})
}
});
// 返回promise , 完成链式
return promise2;
}
catch(fn) {
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 防止多次调用
let called;
// x 不是 null 并且 x 是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定 , 声明 then = x 的then 方法
let then = x.then;
// 如果 then 是函数 , 就默认是 promise了
if (typeof then === 'function') {
// 就让 then 执行 第一个参数是 this 后面是成功的回调和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve 的结果依旧是 promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err); // 失败了就失败了
})
} else {
resolve(x); //直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了 那就不要再继续执行了
reject(e);
}
} else {
resolve(x);
}
}
Конечно, есть метод навешивания на промис
// resolve方法
Promise.resolve = function(val) {
return new Promise((resolve,reject)=>{
resolve(val)
})
}
// reject方法
Promise.reject = function(val) {
return new Promise((resolve,reject)=> {
reject(val);
})
}
// all 方法 (获取所有的promise , 都执行then , 把结果放到数组 , 一起返回, 如果其中有一个发送了reject ,
则取出失败的时候最先被reject失败状态的值)
// 这个方法比较常用 , 一般用于 并发请求数据 ,ajax并发请求数据
Promise.all = function(promises) {
let arr = [];
let i = 0;
functionData(index,data) {
arr[index] = data;
i++;
if(i == promises.length) {
resolve(arr);
}
}
return new Promise((resolve,reject) => {
for(let i = 0 ; i < promises.length ; i ++) {
promises[i].then(data => {
processData(i,data);
},reject)
}
})
}
// race方法
// mdn的解释:
Promise.race()一旦可迭代的promise中的一个承诺实现或拒绝,该方法就会返回一个承诺,该承诺中包含承诺的价值或原因。
// 还是比较好理解的
Promise.race = function(promises) {
return new Promise((resolve,reject) =>{
for(let i = 0 ; i < promises.length ; i++) {
promises[i].then(resolve,reject);
}
})
}
// 用法大概是下面这样了
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 1000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 900);
})
Promise.race([p1, p2]).then((result) => {
console.log(result) // success
})
использованная литература
- «Глубокое понимание ES6», Electronic Industry Press.
- Классические вопросы для интервью с интерфейсом BAT: самое подробное рукописное руководство по Promise в истории