Итак, вы такое обещание

внешний интерфейс JavaScript Promise ECMAScript 6

1. Введение в промисы

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

Например, мне нужно: --(задержка 1 с) --> вывод 1 --(задержка 2 с) --> вывод 2 --(задержка 3 с) --> вывод 3, обычно пишется так:

setTimeout(()=> {
    console.log('1');
    setTimeout(()=> {
        console.log('2');
        setTimeout(()=> {
            console.log('3'); 
        }, 3000)
    }, 2000)
}, 1000)

Такие множественные вложенные обратные вызовы называются адом обратных вызовов, и такой код плохо читается и сложен для понимания.

Если вы используете обещания, стиль рисования изменится

function delay(time, num) {
    return new Promise((res, rej)=> {
        setTimeout(()=> {
            console.log(num);
            res();
        }, time*1000)
    });
}
delay(1, 1).then(()=> {
    return delay(2, 2);
}).then(()=> {
    delay(3, 3);
})

Используется цепной вызов промисов, а структура кода понятнее.

Разве это не здорово? Тогда не торопись и бери~

2. Использование обещаний

Метод вызова следующий:

new Promise((resolve, reject)=> {
    if('some option') {
        resolve('some value');
    } else {
        reject('some error');
    }
}).then(
    val=> {
        // ...
    },
    error=> {
        // ...
    }
)

Конструктор Promise получает функциональный параметр fn, fn имеет два параметра, а именно: resolve, reject, Promise также имеет метод Promise.prototype.then, который получает два параметра, а именно успешный обратный вызов функции succ и отказ функции обратного вызова error.

Вызов разрешения в fn вызовет обратный вызов succ, а вызов reject вызовет обратный вызов ошибки.

2.1 Передача параметров

  • Параметры, переданные при вызове разрешения/отклонения внутри fn, будут переданы в соответствующую функцию обратного вызова в качестве соответствующих параметров.
new Promise((res, rej)=> {
    res('happy')
}).then(val=> {
    console.log(val);  // happy
});

new Promise((res, rej)=> {
    rej('error!');
}).then(val=> {}, err=> {
    console.log(err);  // error!
});
  • При цепочке вызовов, если на предыдущий уровень не передается значение, значение по умолчанию не определено.
new Promise((res, rej)=> {
    res('a');    
}).then(val=> {
    return 'b'
}).then(val=> {
    console.log(val);  // 'b'
}).then((val)=> {
    console.log(val);  // 'undefined'
});
  • Если значение then, переданное на предыдущем уровне, не является функцией, этот уровень игнорируется.
new Promise((res, rej)=> {
    res('a');    
}).then(val=> {
    return 'b';
}).then(val=> {
    console.log(val);  // 'b'
	return 'c';
}).then({  // 并非函数
    name: 'lan'
}).then((val)=> {
    console.log(val);   // 'c'
});

2.2 Пример передачи параметров

let doSomething = function() {
    return new Promise((resolve, reject) => {
        resolve('返回值');
    });
};

let doSomethingElse = function() {
    return '新的值';
}

doSomething().then(function () {
    return doSomethingElse();
}).then(resp => {
    console.warn(resp);
    console.warn('1 =========<');
});

doSomething().then(function () {
    doSomethingElse();
}).then(resp => {
    console.warn(resp);
    console.warn('2 =========<');
});

doSomething().then(doSomethingElse()).then(resp => {
    console.warn(resp);
    console.warn('3 =========<');
});

doSomething().then(doSomethingElse).then(resp => {
    console.warn(resp);
    console.warn('4 =========<');
});

В сочетании с приведенным выше объяснением, каков будет результат? (Ответы и анализ)

3. Promise.prototype.then

Когда состояние в Обещании (pending ---> resolved or rejected) будет выполняться только при изменении метода then.

  • Позвоните тогда вернули еще пример обещания (так что это можно привязать звонки ...)
new Promise((res, rej)=> {
    res('a');
}).then(val=> {
    return 'b';
});

// 等同于
new Promise((res, rej)=> {
    res('a');
}).then(val=> {
    return new Promise((res, rej)=> {
        res('b');
    });
});
  • Обратные вызовы в then всегда выполняются асинхронно
new Promise((res, rej)=> {
    console.log('a');
    res('');
}).then(()=> {
    console.log('b');
});
console.log('c');
// a c b
  • Если вы не вызываете разрешение или отклонение в функции параметра обещания, тогда метод then никогда не будет запущен.
new Promise((res, rej)=> {
    console.log('a'); 
}).then(()=> {
    console.log('b');
});
console.log('c'); 
// a c

4. Статический метод Promise

Promise также имеет четыре статических метода:resolve,reject,all,race, давайте представим их один за другим.

4.1 Promise.resolve()

В дополнение к новому методу Promise() у нас также есть два метода для создания объектов Promise: Promise.resolve() эквивалентен созданию объекта с немедленным разрешением. Следующие два фрагмента кода работают одинаково:

Promise.resolve('a');

new Promise((res, rej)=> {
    res('a');
});

Конечно, Promise.resolve() будет выполнять разные операции в зависимости от переданных параметров.

  • Параметр является экземпляром Promise

Если аргумент является экземпляром Promise, то Promise.resolve вернет экземпляр без изменений и без изменений.

  • Параметр является доступным объектом

Объект thenable относится к объекту с методом then, например к следующему объекту.

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Метод Promise.resolve преобразует этот объект в объект Promise, а затем немедленно выполнит метод then объекта, который можно использовать.

  • аргумент не является объектом с методом then или вообще не является объектом

Если аргумент является примитивным значением или объектом без метода then, метод Promise.resolve возвращает новый объект Promise с состоянием разрешения.

  • без параметров

Метод Promise.resolve позволяет вызывать без параметров и напрямую возвращает разрешенный объект Promise.

Кое-что стоит отметитьОн заключается в том, что статический метод вызывается перед окончанием опроса этого события, а не в начале опроса следующего события. Про опрос событий можно посмотреть здесь -->Подробное объяснение механизма работы JavaScript: снова поговорим о цикле событий

4.2 Promise.reject()

Аналогичен Promise.resolve(), за исключением того, что один из них является обратным вызовом, который вызывает успех, а другой — обратным вызовом, который вызывает сбой.

4.3 Promise.all()

Метод all Promise предоставляет возможность выполнять асинхронные операции параллельно и выполнять обратные вызовы после выполнения всех асинхронных операций.

function asyncFun1() {
	return new Promise((res, rej)=> {
		setTimeout(()=> { 
			res('a');
		}, 1000);
	}); 
}
function asyncFun2() {
	return new Promise((res, rej)=> {
		setTimeout(()=> { 
			res('b');
		}, 1000);
	}); 
}
function asyncFun3() {
	return new Promise((res, rej)=> {
		setTimeout(()=> { 
			res('c');
		}, 1000);
	}); 
}
Promise.all([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {
    console.log(val);
});
Promise.all([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {
    console.log(val);  // ['a', 'b', 'c']
});

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

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

4.4 Promise.race()

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

Promise.race([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {
    console.log(val);  // a
});

5. Классический пример цепного вызова

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

写一个类Man实现以下链式调用

调用方式:
new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');
打印:
'hello, lan' -(等待3s)--> 'lan eat apple' -(等待5s)--> 'lan eat banana'

Идеи:

  • Верните это в метод прототипа, чтобы достичь цели цепочки вызовов.
  • Эффект ожидания выполнения 3 с может быть достигнут с помощью Promise, а затем

Конкретная реализация выглядит следующим образом:

class Man {
    constructor(name) {
        this.name = name;
        this.sayName();
        this.rope = Promise.resolve();  // 定义全局Promise作链式调用
    }
    sayName() {
        console.log(`hello, ${this.name}`);
    }
    sleep(time) {
        this.rope = this.rope.then(()=> {
            return new Promise((res, rej)=> {
                setTimeout(()=> {
                    res();
                }, time*1000);
            });
        });
        return this;
    }
    eat(food) {
        this.rope = this.rope.then(()=> {
            console.log(`${this.name} eat ${food}`); 
        });

        return this;
    }
}

new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');

OK! Я не знаю, понимаешь ли ты? Если вы можете полностью понять код, ваше обещание можно очистить, кстати, у вас есть небольшое мышление? В чем разница, чем выше? :

class Man1345 {
    constructor(name) {
        this.name = name;
        this.sayName(); 
    }
    sayName() {
        console.log(`hello, ${this.name}`);
    }
    sleep(time) { 
        this.rope = new Promise((res, rej)=> {
                setTimeout(()=> {
                    res();
                }, time*1000);
            }); 
        return this;
    }
    eat(food) {
        this.rope = this.rope.then(()=> { 
            console.log(`${this.name} eat ${food}`);  
        });

        return this;
    }
}

new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');

Проще говоря, результат выполнения второго куска кода

'hello, lan' -(等待3s)--> 'lan eat apple' ---> 'lan eat banana'

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

Похожий на

var time1 = setTimeout(()=> {
	console.log('a');
}, 1000)
var time2 = setTimeout(()=> {
	console.log('b');
}, 1000)
// 同时输出 a b

Абстрактное объяснение:

// 第一段正确的代码的执行为
var p1 = new Promise().then('停顿3s').then('打印食物').then('停顿5s').then('打印食物');

// 第二段代码的执行行为,p1、p2异步并行执行
var p1 = new Promise().then('停顿3s').then('打印食物');
var p2 = new Promise().then('停顿5s').then('打印食物');

Суммировать

Обещания часто используются в следующих местах:

  • Выбраться из ада обратного вызова
  • Несколько асинхронных задач

Promise — хороший помощник для нас, но есть и другой способ сделать это — async&await, вы можете узнать о нем подробнее.

использованная литература

Начало работы с ECMAScript 6

Простое и простое понимание then в Promise

Объясните обещание на местном языке