- Оригинальный адрес:9 Promising Promise Tips
- Оригинальный автор:Kushan Joshi
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:position_ грейпфрутовый джентльмен
- Корректор:Starrier, DukeWu
Как говорят коллеги, обещания преуспевают в работе.
Эта статья даст вам несколько советов о том, как улучшить ваши отношения с промисами.
1. Вы можете вернуть обещание в .then
Поясню самый важный момент
Да! Вы можете вернуть Promise внутри .then
Кроме того, это Обещание, которое возвращается, будет в следующем.then
автоматически анализируется.
.then(r => {
return serverStatusPromise(r); // 返回 { statusCode: 200 } 的 Promise
})
.then(resp => {
console.log(resp.statusCode); // 200; 注意自动解析的 promise
})
2. Новое обещание автоматически создается каждый раз, когда выполняется .then.
Если вы знакомы со стилем цепочки javascript, он должен показаться вам знакомым. Но для новичка, наверное, нет.
В Promises независимо от того, что вы используете.then
или.catch
создаст новое обещание. Это Обещание - это Обещание, только что связанное и только что добавленное..then
/ .catch
Комбинация.
Давайте посмотрим на один 🌰:
var statusProm = fetchServerStatus();
var promA = statusProm.then(r => (r.statusCode === 200 ? "good" : "bad"));
var promB = promA.then(r => (r === "good" ? "ALL OK" : "NOTOK"));
var promC = statusProm.then(r => fetchThisAnotherThing());
Взаимосвязь вышеупомянутого промиса можно четко описать на блок-схеме:
Особо следует отметить, чтоpromA
,promB
а такжеpromC
Все разные, но связанные промисы.
мне нравится ставить.then
Подумайте о большом трубопроводе, по которому вода перестает течь вниз по течению, когда вышестоящий узел выходит из строя. Например, еслиpromB
выходит из строя, нижестоящие узлы не затрагиваются, но еслиstatusProm
выходит из строя, то будут затронуты все нижестоящие узлы, т.е.rejected
.
3. Для вызывающего абонентаPromise
изresolved/rejected
состояние уникально
Я думаю, что это одна из самых важных вещей, чтобы обещания работали хорошо. Проще говоря, если промисы используются многими разными модулями в вашем приложении, то когда промисы возвращаютсяresolved/rejected
состояние, все вызывающие абоненты будут уведомлены.
Это также означает, что никто не может изменить ваше Обещание, поэтому его можно безопасно передать.
function yourFunc() {
const yourAwesomeProm = makeMeProm();
yourEvilUncle(yourAwesomeProm); // 无论 Promise 受到了怎样的影响,它最终都会成功执行
return yourAwesomeProm.then(r => importantProcessing(r));
}
function yourEvilUncle(prom) {
return prom.then(r => Promise.reject("destroy!!")); // 可能遭受的影响
}
Как видно из приведенного выше примера, обещания спроектированы таким образом, чтобы их было трудно изменить. Как я сказал выше: «Сохраняйте спокойствие и передайте Обещание».
4. Конструкторы промисов — не решение
Я вижу, что многим разработчикам нравится стиль конструктора, они думают, что таковы и промисы. Но это ложь, на самом деле причина в том, что API конструктора похоже на API предыдущей функции обратного вызова, и такие привычки трудно изменить.
Если вы обнаружите, что используете везде
Promise 构造函数
, то ваш подход неверен!
Чтобы действительно сделать шаг вперед и избавиться от обратных вызовов, нужно быть осторожным и использовать конструктор Promise по минимуму.
Давайте посмотрим на использованиеPromise 构造函数
Конкретная ситуация:
return new Promise((res, rej) => {
fs.readFile("/etc/passwd", function(err, data) {
if (err) return rej(err);
return res(data);
});
});
Promise 构造函数
долженИспользуйте, только если вы хотите преобразовать обратные вызовы в обещания.
Как только вы освоите этот элегантный способ создания обещаний, он станет очень привлекательным.
давайте посмотрим на лишнееPromise 构造函数
.
☠️Неправильно
return new Promise((res, rej) => {
var fetchPromise = fetchSomeData(.....);
fetchPromise
.then(data => {
res(data); // 错误!!!
})
.catch(err => rej(err))
})
💖правильный
return fetchSomeData(...); // 正确的!
использоватьPromise 构造函数
Обертывание обещанияизлишним и противоречит цели самого обещания.
😎Расширенные советы
если выnodejsРазработчики, предлагаю посмотретьutil.promisify. Этот метод помогает вам преобразовать обратные вызовы в стиле узла в обещания.
const {promisify} = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
readFileAsync('myfile.txt', 'utf-8')
.then(r => console.log(r))
.catch(e => console.error(e));
5. Использование обещания
Javascript предоставляетPromise.resolve
метод, такой же краткий, как следующий пример:
var similarProm = new Promise(res => res(5));
// ^^ 等价于
var prom = Promise.resolve(5);
Он имеет несколько вариантов использования, один из моих любимых — преобразование обычных (асинхронных) объектов js в промисы.
// 将同步函数转换为异步函数
function foo() {
return Promise.resolve(5);
}
Вы также можете сделать безопасную оболочку, когда не уверены, является ли это обещанием или простым значением.
function goodProm(maybePromise) {
return Promise.resolve(maybePromise);
}
goodProm(5).then(console.log); // 5
var sixPromise = fetchMeNumber(6);
goodProm(sixPromise).then(console.log); // 6
goodProm(Promise.resolve(Promise.resolve(5))).then(console.log); // 5, 注意,它会自动解析所有的 Promise!
6. Используйте Promise.reject
Javascript также обеспечиваетPromise.reject
метод. Так же кратко, как следующий пример:
var rejProm = new Promise((res, reject) => reject(5));
rejProm.catch(e => console.log(e)) // 5
Мое любимое использование - использовать заранееPromise.reject
отказаться.
function foo(myVal) {
if (!mVal) {
return Promise.reject(new Error('myVal is required'))
}
return new Promise((res, rej) => {
// 从你的大回调到 Promise 的转换!
})
}
Проще говоря, используйтеPromise.reject
Вы можете отклонить любое Обещание, которое хотите отклонить.
В приведенном ниже примере я.then
Внутреннее использование:
.then(val => {
if (val != 5) {
return Promise.reject('Not Good');
}
})
.catch(e => console.log(e)) // 这样是不好的
Примечание: вы можете сделать что-то вродеPromise.resolve
тоже самоеPromise.reject
передать любое значение. Что вы часто находите в невыполненных обещанияхError
Причина в том, что он в основном используется для выдачи асинхронной ошибки.
7. Использование Promise.all
Javascript предоставляетPromise.allметод. Как ... это краткое, ну, я не могу придумать пример 😁.
В псевдоалгоритмеPromise.all
можно резюмировать как:
接收一个 Promise 数组
然后同时运行他们
然后等到他们全部运行完成
然后 return 一个新的 Promise 数组
他们其中有一个失败或者 reject,都可以被捕获。
В следующем примере показаны все выполненные промисы:
var prom1 = Promise.resolve(5);
var prom2 = fetchServerStatus(); // 返回 {statusCode: 200} 的 Promise
Proimise.all([prom1, prom2])
.then([val1, val2] => { // 注意,这里被解析成一个数组
console.log(val1); // 5
console.log(val2.statusCode); // 200
})
В следующем примере показано, что происходит, когда один из них выходит из строя:
var prom1 = Promise.reject(5);
var prom2 = fetchServerStatus(); // 返回 {statusCode: 200} 的 Promise
Proimise.all([prom1, prom2])
.then([val1, val2] => {
console.log(val1);
console.log(val2.statusCode);
})
.catch(e => console.log(e)) // 5, 直接跳转到 .catch
Уведомление:Promise.all
очень умный! Если одно из обещаний не выполняется, оно не ждет, пока все обещания будут выполнены, а немедленно прерывается!
8. Не бойтесь отклонять, и не добавляйте избыточности в каждый .потом обратно.catch
Мы не часто беспокоимся о том, что ошибки проглатываются где-то между ними?
Чтобы преодолеть этот страх, вот простой совет:
Позвольте отклонению обрабатывать проблемы с вышестоящими функциями.
В идеале метод отклонения должен быть корнем приложения, и все отклонения будут передаваться вниз.
Не бойтесь писать, как показано ниже
return fetchSomeData(...);
Теперь, если вы хотите обработать случай отклонения в функции, решите, следует ли исправить проблему или продолжить отклонение.
💘разрешить отклонить
Разрешить отклонение просто, в.catch
Все, что вы вернете, будет считаться решенным. Однако, если вы.catch
вернуться вPromise.reject
, то обещание не будет выполнено.
.then(() => 5.length) // <-- 这里会报错
.catch(e => {
return 5; // <-- 重新使方法正常运行
})
.then(r => {
console.log(r); // 5
})
.catch(e => {
console.error(e); // 这个方法永远不会被调用 :)
})
💔отклонить отказ
Отказ от отказа прост.Ничего не нужно делать.Как я только что сказал, сделайте это проблемой с другими функциями. Обычно родительская функция имеет лучший способ обработки отклонения, чем текущая функция.
Важно помнить, что когда вы пишете метод catch, вы имеете дело с ошибкой. это и синхронизироватьtry/catch
работает аналогично.
Если вы хотите перехватить отклонение: (я настоятельно не рекомендую этого делать!)
.then(() => 5.length) // <-- 这里会报错
.catch(e => {
errorLogger(e); // 做一些错误处理
return Promise.reject(e); // 拒绝它,是的,你可以这么做!
})
.then(r => {
console.log(r); // 这个 .then (或者任何后面的 .then) 将永远不会被调用,因为我们在上面使用了 reject :)
})
.catch(e => {
console.error(e); //<-- 它变成了这个 catch 方法的问题
})
Разделительная линия между .then(x,y) и then(x).catch(x)
.then
接收的第二个回调函数参数也可以用来处理错误。 И этоthen(x).catch(x)
Это выглядит похоже, но разница в том, как они обрабатывают ошибки, заключается в ошибках, которые они ловят сами.
Я проиллюстрирую это следующим примером:
.then(function() {
return Promise.reject(new Error('something wrong happened'));
}).catch(function(e) {
console.error(e); // something wrong happened
});
.then(function() {
return Promise.reject(new Error('something wrong happened'));
}, function(e) { // 这个回调处理来自当前 `.then` 方法之前的错误
console.error(e); // 没有错误被打印出来
});
Если вы хотите обрабатывать Promise из апстрима, а не только из.then
При добавлении к нему ошибки.then(x,y)
Стало очень удобно.
Совет: в 99,9% случаев используются простыеthen(x).catch(x)
лучше.
9. Избегайте .then callback hell
Этот совет относительно прост, старайтесь избегать.then
содержит.then
или.catch
. Поверьте, этого легче избежать, чем вы думаете.
☠️Неправильно
request(opts)
.catch(err => {
if (err.statusCode === 400) {
return request(opts)
.then(r => r.text())
.catch(err2 => console.error(err2))
}
})
💖правильный
request(opts)
.catch(err => {
if (err.statusCode === 400) {
return request(opts);
}
})
.then(r => r.text())
.catch(err => console.erro(err));
иногда мы.then
Вам нужно много переменных внутри, тогда у вас нет выбора, кроме как создать еще одну.then
цепочка методов.
.then(myVal => {
const promA = foo(myVal);
const promB = anotherPromMake(myVal);
return promA
.then(valA => {
return promB.then(valB => hungryFunc(valA, valB)); // 很丑陋!
})
})
Я рекомендую использовать метод деструктурирования ES6, смешанный сPromise.all
способ может решить эту проблему.
.then(myVal => {
const promA = foo(myVal);
const promB = anotherPromMake(myVal);
return Promise.all([prom, anotherProm])
})
.then(([valA, valB]) => { // 很好的使用 ES6 解构
console.log(valA, valB) // 所有解析后的值
return hungryFunc(valA, valB)
})
Примечание. Если ваш узел / браузер / босс / Осознание позволяет использовать, вы можете использоватьasync/awaitметод решения этой проблемы.
Я очень надеюсь, что эта статья помогла вам понять промисы.
Пожалуйста, ознакомьтесь с моим предыдущим сообщением в блоге.
- Руководство для начинающих по проблемам утечки памяти Javascript
- Понимание параметров по умолчанию в Javascript
Если вы ❤️ этот пост, пожалуйста, поделитесь этим постом, чтобы распространить его.
Свяжитесь со мной в Twitter@kushan2020.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.