Promise
Обещайте продвижение, все, что вам нужно, здесь
основное содержание:
- Основной принцип обещания
- Сложности с использованием промисов (цепные вызовы, API в основном возвращает новый промис и передача параметров)
- Обещания обрабатывают исключения
- Простая реализация и спецификация обещания
- ES6 более подробно рассматривает промисыАсинхронное обновление - полностью понятно
Ссылаться на:
0. Основное использование
Базовое использование промисов, чтение этой статьи необходимо для понимания основныхPromise
использовать.
1. Совместимость
Проверка совместимости В принципе, проблем с поддержкой основных браузеров нет.
Проблема несовместимости IE, в этой статье она не будет рассматриваться, выйдите и поверните налево, ищите Брата Гу. Проверьте этоbabel, или реализовать обещание самостоятельно
2. Инкапсуляция ajax XMLHttpRequest
//get 请求封装
function get(url) {
// Return a new promise.
return new Promise(function(resolve, reject) {
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
// This is called even on 404 etc
// so check the status
if (req.status == 200) {
// Resolve the promise with the response text
resolve(req.response);
}
else {
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
};
// Handle network errors
req.onerror = function() {
reject(Error("Network Error"));
};
// Make the request
req.send();
});
}
1. Promse API
API Promise делится на:MDN
-
статический метод
-
prototype
вышеуказанный методPromise.prototype.then()
анализировать首先来看看 `Promise.prototype.then()`返回一个`Promise`,但`Promise`内部有返回值,且 返回值,可以是个值,也可能就是一个新`Promise` *具体规则如下:*
- Если функция обратного вызова в then возвращает значение, то обещание, возвращенное then, станет состоянием принятия, а возвращенное значение будет использоваться в качестве значения параметра функции обратного вызова в состоянии принятия.
- Если функция обратного вызова в then выдает ошибку, то обещание, возвращенное then, станет состоянием отклонения, и выброшенная ошибка будет использоваться в качестве значения параметра функции обратного вызова в состоянии отклонения.
- Если функция обратного вызова в then возвращает промис, который уже находится в состоянии принятия, то промис, возвращенный к тому времени, также станет состоянием принятия, а значение параметра функции обратного вызова в состоянии принятия этого промиса будет использоваться как принятие функции обратного вызова состояния возвращенного значения параметра Promise.
- Если функция обратного вызова в then возвращает промис, который уже отклонен, то промис, возвращенный к тому времени, также будет отклонен, и значение параметра функции обратного вызова состояния отклонения этого промиса будет использоваться в качестве функции обратного вызова состояния отклонения возвращаемое значение параметра Promise.
- Если функция обратного вызова в then возвращает промис с неопределенным состоянием (ожидание), то состояние промиса, возвращенного до этого момента, также не определено, и его конечное состояние совпадает с окончательным состоянием этого промиса; в то же время, обратный вызов вызывается, когда он становится окончательным. Параметры функции совпадают с параметрами функции обратного вызова, когда обещание становится окончательным.
Вышеупомянутое является официальными правилами, бог конь, конкретный жаргон заключается в том, что ядром является состояние возврата параметров и возврата обещаний.
Ссылаться на:MDN
Чувствуете ли вы головокружение? Это не имеет значения. Сначала вы можете прочитать следующий раздел. После его прочтения вернитесь и прочтите конкретные инструкции.
/*then 回调中, 1. 返回是return function,则返回一个Promise 【参见对比3代码】 2. 不是一个function,则 then 将创建一个没有经过回调函数处理的新 Promise 对象,这个新 Promise 只是简单地接受调用这个 then 的原 Promise 的终态作为它的终态。(MDN中解释)【参见对比1代码】 3. 返回一个function,但没有return ,则相当于 then(null) */ //对比1 穿透问题 返回是'foo' 而不是 'bar' Promise.resolve('foo').then(Promise.resolve('bar')).then(function(result){ console.log(result) }) //对比2 打印undefined Promise.resolve('foo').then(function(){Promise.resolve('bar')}).then(function(result){ console.log(result) }) //对比3 返回 'bar' Promise.resolve('foo').then(function() { return Promise.resolve('bar') }).then(function(result) { console.log(result) })
2. Цепочка обещаний
цепной вызов
- Суть в том, что такие методы, как then catch, возвращают Promise
- Передача данных связанного вызова (примечание)
1. Значение проблем доставки
Простой пример
//正常状态
const promise1 = new Promise((resolve, reject) => {
resolve('0000')//
})
promise1.then(result => {
console.log(result) //0000
return '1111';//类似于 return Promise.resolve('1111'); 参数是data,promise 状态时 resolve
}).then(data => {
console.log(data) // 1111
})
Практический пример: (возьмем пример великого богаОбещания JavaScript: введение)
get('story.json').then(function(response) {
console.log("Success!", response);
})
//这里的 response 是 JSON,但是我们当前收到的是其纯文本。也可以设置XMLHttpRequest.responseType =json
get('story.json').then(function(response) {
return JSON.parse(response);
}).then(function(response) {
console.log("Yey JSON!", response);
})
//由于 JSON.parse() 采用单一参数并返回改变的值,因此我们可以将其简化为:
get('story.json').then(JSON.parse).then(function(response) {
console.log("Yey JSON!", response);
})
function getJSON(url) {
return get(url).then(JSON.parse);
}
//getJSON() 仍返回一个 promise,该 promise 获取 URL 后将 response 解析为 JSON。
2. Очередь асинхронных операций
Вышеупомянутое до сих порreturn 值
, сразу вызовите следующийthen
Просто нормально.
но еслиreturn Promise
,но?
Promise.resolve(111).then(function(d){
console.log(d);
return Promise.resolve(d+111);//返回promise
}).then(function(d2){
console.log(d2);
})
// 111,222
3. Параллельная задача для каждой обработки
Когда несколько асинхронных исполнений выполняются параллельно, время выполнения каждого асинхронного кода является неопределенным, поэтому время окончания нескольких асинхронных исполнений не может быть определено (время окончания не может быть определено).
Поэтому требуется особая обработка.
//forEach 顺便无法保证
var arrs = [1,2,3,4];
var p = function(d){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(d);
},Math.random()*1000);//因为异步执行时间无法确认
});
};
arrs.forEach(function(arr){
p(arr).then((d)=>{
console.log(d);
})
});
//使用 Promise.all 来让返回有序
var arrs = [1,2,3,4];
var p = function(d){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(d);
},Math.random()*1000);//因为异步执行时间无法确认
});
};
var ps = [];
arrs.forEach(function(arr){
ps.push(p(arr));
});
Promise.all(ps).then(values=>{
console.log(values);//[1,2,3,4]
})
4. Основной принцип реализации — реализация простого обещания
Сделай сам простойPromise
1. Версия 1 - Минимальная реализация
//版本1 极简实现
function Promise1(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;//支持链式调用 Promise.then().then
};
function resolve(value) {
callbacks.forEach(function (callback) {
callback(value);
});
}
fn(resolve);
}
//Test 对上面实现,写一个简单的测试
new Promise1(function(resolve){
setTimeout(function(){
resolve(1);
},100);
}).then(function(d){
console.log(d);
})
//1
2. Версия 2 — Добавление механизма задержки
//上面版本1 可能导致问题
//在then注册回调之前,resolve就已经执行了
new Promise1(function(resolve){
console.log(0)
resolve(1);
}).then(function(d){
console.log(d);
})
// 1 不会打印
//版本2 解决
function Promise1(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;//支持链式调用 Promise.then().then
};
function resolve(value) {
setTimeout(function(){
callbacks.forEach(function (callback) {
callback(value);
}),0});
}
fn(resolve);
}
3. Версия 3 — Статус
Promise
Есть три состоянияpending
,fulfilled
,rejected
, а изменения состояния однонаправлены.
Конкретные подробности вthen
,resolve
Решение о статусе Китая и Канады, конкретный код опущен
4. Promises/A+
специфическийPromise
Существует набор официальных спецификаций для реализации, см.Promises/A+
5. наконец реализация
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
6. Обработка исключений
Классификация исключений:
- Исключение синхронизации
- Ошибка асинхронного исключения
try-catch
получать- Многоуровневое вложение обещаний, получить исключение, чтобы получить конкретное исключение обещания, а не все
1. Базовая процедура обработки исключений Promise
В базовой обработке исключений есть два вариантаthen(undefined, func)
а такжеcatch()
ноthen(undefined, func)
а такжеcatch()
разные, подробности см. в кодеСценарий 3
//方案1 使用 Promise.prototype.catch()来catch
const promise1 = new Promise((resolve, reject) => {
reject('no')//
})
promise1.then(result => {
console.log(result) // 永远不会执行
}).catch(error => {
console.log(error) // no
})
//方案2 使用 Promise.prototype.then()中第二个参数 来处理
const promise1 = new Promise((resolve, reject) => {
reject('no')//
})
promise1.then(result => {
console.log(result) // 永远不会执行
},error => {
console.log(error) // no
})
//方案2 (方案1 方案2 对比)
var promise2 = new Promise((resolve, reject) => {
resolve('yes')//
})
promise2.then(result => {
throw new Error('then');
console.log(result)
},error => {
console.log('1111',error) // no
}).catch(error=>{
console.log('2222',error)// 最终 err在此处被捕获,而不是 then 中
})
2. Различные категории исключений
Типы исключений, с которыми могут столкнуться промисы
//1.异常 reject()
const promise1 = new Promise((resolve, reject) => {
reject('no')//
})
promise1.then(result => {
console.log(result) // 永远不会执行
}).catch(error => {
console.log(error) // no
})
//2.异常 显示throw
const promise1 = new Promise((resolve, reject) => {
throw Error('no')
})
promise1.then(result => {
console.log(result) // 永远不会执行
}).catch(error => {
console.log(error) //
})
//3.执行异常
const promise1 = new Promise((resolve, reject) => {
aaaa;
})
promise1.then(result => {
console.log(result) // 永远不会执行
}).catch(error => {
console.log(error) //
})
3. Вызов цепочки исключений
asyncThing1().then(function() {
return asyncThing2();
}).then(function() {
return asyncThing3();
}).catch(function(err) {
return asyncRecovery1();
}).then(function() {
return asyncThing4();
}, function(err) {
return asyncRecovery2();
}).catch(function(err) {
console.log("Don't worry about it");
}).then(function() {
console.log("All done!");
})
Блок-схема приведенного выше кода:
// promise链式调用,catch住异常后,后面就不会处理异常了
Promise.reject().then(()=>{
console.log(2222);
},(err)=>{
console.log(333,err)
return err})
.catch((err)=>{
console.log(1111,err);
})
//333 undefined ,没有打印 1111
//如果 在链式调用中,then 第二个参数 catch住了异常,没有return Promise.reject()则后续链式调用返回rosolve状态pormise
Promise.reject()
.then(()=>{
console.log(111);
},(err)=>{
console.log(111,err) //reject
return err;
}).then((data)=>{
console.log(222,data);//resolve 执行
},(err)=>{
console.log(222,err); //未执行
})
//4444 没有执行 1111
4. Ненормальная потеря
Во многих случаях промисы не могут перехватывать исключения.
Сцена 1Исключение выбрасывается в очередь макрозадач:
//场景1
//永远不要在 macrotask 队列中抛出异常,因为 macrotask 队列脱离了运行上下文环境,异常无法被当前作用域捕获。
function fetch(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
throw Error('用户不存在')
})
})
}
fetch().then(result => {
console.log('请求处理', result) // 永远不会执行
}).catch(error => {
console.log('请求处理异常', error) // 永远不会执行
})
// 程序崩溃
// Uncaught Error: 用户不存在
/*
参考
作者:黄子毅
链接:https://www.jianshu.com/p/78dfb38ac3d7
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
*/
//解决场景1 怎么解决,因为setTimeout 是macrotask任务,执行上下文完全不同
/**
如何解决?
调用reject
*/
function fetch() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('收敛一些')
})
})
}
fetch().then((resolve, reject) => {
console.log('resolve');
}).catch(error => {
console.log('捕获异常', error) // 捕获异常 收敛一些
})
сцена втораяСостояние обещания можно изменить только один раз
//异常丢失
const promise2 = new Promise((resolve, reject) => {
reject('no')
console.log('reject after')
throw Error('no') //异常丢失
})
promise1.then(result => {
console.log(result) // 永远不会执行
}).catch(error => {
console.log('err',error) // no
}).catch(error => {
console.log('err2',error) // 也无法捕获异常
})
7.async
async — это инкапсуляция Promise более высокого уровня.Коротко об асинхронности