Как мы все знаем, Javascript — это однопоточный язык, и весь код должен выполняться в так называемом порядке «сверху вниз». Проблема с этой функцией заключается в том, что некоторые будущие неизвестные операции должны быть реализованы асинхронно (об асинхронности я расскажу в другой статье). В этой статье будет обсуждаться относительно распространенное асинхронное решение — промисы, которые на момент последнего обновления этой статьи широко использовались.
Проблемы, которые решают обещания
Я считаю, что каждый интерфейс сталкивался с такой проблемой. Когда выполнение асинхронной задачи должно зависеть от результата другой асинхронной задачи, мы обычно вкладываем две асинхронные задачи. Это происходит один или два раза. Потерпите, но после этого случается много, ваш код будет выглядеть как этот медведь:
async1(function(){
async2(function(){
async3(function(
async4(funciton(){
async5(function(){
//(╯°□°)╯︵┻━┻
//...
});
});
));
});
});
Это так называемый callback hell.Код вложенный и взаимосвязанный.Очевидно, что логика немного сложнее, и такую программу будет сложно поддерживать.
Для этой ситуации программисты придумали множество решений (таких как модульность кода), но с точки зрения управления процессом они до сих пор не убрали много вложенности }). Однако в прошлогоднем стандарте ES2015 стандартизация Promise в определенной степени решила проблему работы процессов JavaScript.
Основное использование промисов
Сегодня его реализовали многие современные браузеры, но для совместимости рекомендуется инкапсулировать Promise самостоятельно или использовать стороннее решение (например, webpack для компиляции синтаксиса es6). Затем мы получим конструктор Promise и создадим новый экземпляр Promise:
var _promise = new Promise(function(resolve, reject){
setTimeout(function(){
var rand = Math.random();
if(rand<0.5){
resolve("resolve" + rand);
}else{
reject("reject" + rand);
}
},1000);
});
/*运行结果:
*有两种情况:
*1)无事发生
*2)报错形如:d.js:7 Uncaught (in promise) reject0.9541820247347901
*/
Как показано выше, конструктор промиса принимает в качестве параметра функцию, которая принимает две дополнительные функции, разрешение и отклонение, которые представляют установку текущего промиса в состояние выполнено (разрешено) и отклонено (отклонено) соответственно. Именно через эти два состояния промисы управляют результатами асинхронных операций. Далее мы обсудим использование Promise, на самом деле экземпляр _promise в Promise — это объект, а не функция. При объявлении функция параметра, переданная Promise, будет выполнена немедленно, поэтому правильная поза, используемая Promise, заключается в том, чтобы обернуть другой уровень функции в его внешний слой.
var run = function(){
var _promise = new Promise(function(resolve, reject){
setTimeout(function(){
var rand = Math.random();
if(rand<0.5){
resolve("resolve" + rand);
}else{
reject("reject" + rand);
}
},1000);
});
return _promise;
}
run();
Это нормальное использование Promise, следующим шагом является обработка результата асинхронной операции, а затем функция run(), созданная выше.
run().then(function(data){
console.log(data);
});
У каждого экземпляра объекта Promise есть метод then, который используется для обработки результатов различных асинхронных операций.
Так, Вы можете спросить, Какая польза от этого?
Конечно, это работает, пока мы изучили основной поток промисов, но такое использование, кажется, ничем не отличается от вложенных функций обратного вызова, и это добавляет сложности. Но мы сказали, что польза Promise на самом деле заключается в управлении логическим потоком, когда несколько асинхронных операций взаимозависимы. Обещание решает проблему управления процессом, контролируя два состояния. См. следующий код:
run().then(function(data){
//处理resolve的代码
cosnole.log("Promise被置为resolve",data);
},function(data){
//处理reject的代码
cosnole.log("程序被置为了reject",data);
})
Если асинхронная операция получит желаемый результат, то мы вызовем функцию разрешения, которая может получить данные в первой анонимной функции затем в качестве параметра, если мы получим неправильный результат, вызовем функцию отклонения, в функции затем Второй в качестве параметра получает данные обработки ошибок в анонимной функции. Таким образом завершается полный вызов Promise. Для метода then() в Promise всегда возвращает экземпляр Promise, так что вы всегда можете вызывать then как run().then().then().then().then().then(). .... В состоянии, когда метод then() вызывается успешно асинхронно, вы можете либо вернуть определенное «значение», либо снова вернуть экземпляр Promise. Когда возвращается точное значение, then вернет точное значение. передается в экземпляре Promise по умолчанию, и этот экземпляр Promise немедленно устанавливается в состояние выполнено для использования в следующем методе then. Следующим образом:
run().then(function(data){
console.log("第一次",data);
return data;
}).then(function(data){
console.log("第二次",data);
return data;
}).then(function(data){
console.log("第三次",data);
return data;
});
/* 异步处理成功的打印结果:
第一次 resolve0.49040459200760167d.js:18
第二次 resolve0.49040459200760167d.js:21
第三次 resolve0.49040459200760167
由此可知then方法可以无限调用下去。
*/
В соответствии с этой функцией мы можем управлять несколькими асинхронными логиками, которые зависят друг от друга в порядке сравнения. Возьмем пример с 3 асинхронными операциями, код немного длинный.
//第一个异步任务
function run_a(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
resolve("step1");
});
}
//第二个异步任务
function run_b(data_a){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
console.log(data_a);
resolve("step2");
});
}
//第三个异步任务
function run_c(data_b){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
console.log(data_b);
resolve("step3");
});
}
//连续调用
run_a().then(function(data){
return run_b(data);
}).then(function(data){
return run_c(data);
}).then(function(data){
console.log(data);
});
/*运行结果
step1
step2
step3
*/
Таким образом, несколько асинхронных операций, от которых постоянно зависят, завершаются, что решает головную боль ада обратных вызовов.
Асинхронная операция отклоняет и завершает цепочку вызовов
Как упоминалось ранее, метод then может принимать в качестве параметров две анонимные функции: первый параметр — это обратный вызов после того, как Promise устанавливается в состояние выполнено, а второй — обратный вызов, который устанавливается в отклоненное состояние. Во многих случаях, если есть несколько последовательных асинхронных задач и одна из них не может быть обработана, то следующие несколько задач не должны продолжать обработку в значительной степени, так как же мы завершаем цепочку вызовов then? В экземпляре Promsie, в дополнение к методу then, есть также метод catch.Специфическая функция метода catch заключается в использовании приведенного выше кода для преобразования run_a():
//修改run_a的一步操作可能存在拒绝状态
function run_a(){
return new Promise(function(resolve, reject){
setTimeout(function(){
if(Math.random()>.5){
resolve("step1");
}else{
reject("error");
}
},1000);
});
}
//这样做不会终止
run_a().then(function(data){
return run_b(data);
},function(data){
//如果是这样处理rejected状态,并不会终止调用链
return data;
}).then(function(data){
return run_c(data);
}).then(function(data){
console.log(data);
});
//在调用链的末尾加上catch方法,当某个环节的Promise的异步处理出错时,将终止其后的调用,直接跳到最后的catch
run_a().then(function(data){
return run_b(data);
}).then(function(data){
return run_c(data);
}).then(function(data){
console.log(data);
}).catch(function(e){
//rejected的状态将直接跳到catch里,剩下的调用不会再继续
console.log(e);
});
В приведенном выше коде кратко описано, как завершать вызов цепочки.Стоит отметить, что метод catch также имеет функцию try catch, то есть если в логическом коде есть ошибка, то он не будет выброшен на консоли, но будет прямой захват захвата.
Расширение ES6 для Promise/A+
Промис был предложен очень рано, его стандарт называется Promise/A+, а контента не так много, ES6 прописывает промис в стандарт и расширяет его на его основе, подробнее см.:
· Перевод Promise/A+ от malcolm yud · Ruan Yifeng ES6 Введение - Обещание
Здесь мы поговорим о расширении ES6 до стандарта Promise, или вы можете непосредственно посмотреть ссылку выше.
Расширение Promise.all
Это расширение реализует объединение нескольких асинхронных операций в одну операцию, то есть параллельную асинхронную обработку и, наконец, унификацию результатов операции.Примечание: этот метод можно вызывать только напрямую через объект Promise, и экземпляр не может выполнять эту операцию.
all() получает массив параметров, каждый элемент массива соответствует
//第一个异步任务
function run_a(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
resolve("step1")
});
}
//第二个异步任务
function run_b(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
resolve("step2");
});
}
//第三个异步任务
function run_c(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
resolve("step3");
});
}
Promise.all([run_a(),run_b(),run_c()]).then(function(data){
console.log(data);
},function(data){
console.log(data);
});
/*打印结果
["step1","step2","step3"]
*/
//修改第二个异步任务
//第一个异步任务
function run_b(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
reject("step2")
});
}
/*打印结果
*捕获了第一个出现的拒绝状态的数据
["step2"]
*/
Как показано выше, результаты параллельных операций будут помещены в массив в порядке входных параметров и возвращены.
Расширение Promise.race
Первоначальное значение слова «гонка» — «бежать». Как следует из названия, слово «гонка» используется для параллельного выполнения нескольких асинхронных операций. Победит тот, кто первым обработает конец.
//第一个异步任务
function run_a(){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log("执行到step1");
resolve("step1")
},3000);
});
}
//第二个异步任务
function run_b(){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log("执行到step2");
resolve("step2");
},1000);
});
}
//第三个异步任务
function run_c(){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log("执行到step3");
resolve("step3");
},3000);
});
}
Promise.race([run_a(),run_b(),run_c()]).then(function(results){
console.log(results);
},function(data){
console.log(data);
});
/*
打印结果:
执行到step2
step2
执行到step1
执行到step3
*/
Видно, что run_b выполняется первым, а затем входит в функцию then для обратного вызова, но следует отметить, что после обратного вызова первой завершенной асинхронной операции другие асинхронные операции будут продолжать выполняться, но она не будет продолжаться. вступай тогда. .
Эпилог
Вышеизложенное представляет собой простое понимание промисов в соответствии со стандартом ES6. Промисы существуют уже давно и широко используются во многих проектах с открытым исходным кодом. Понимание промисов поможет вам лучше понять код. Как мой личный отчет об обучении, эта статья надеется сыграть роль в привлечении других и сыграть небольшую роль в обучении каждого.