Я мог придумать
function squareAsync(val, callback) {
if (callback) {
setTimeout(() => {
if (Math.random() < 0.5) {
callback(undefined, val * val);
}
else {
callback(new Error('Failed!'));
}
}, 2000);
}
else {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve(val * val);
}
else {
reject(new Error('Failed!'));
}
}, 2000);
});
}
}
Я нашел другой способ для этого
function squareAsync1(val, callback) {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve(val * val);
}
else {
reject(new Error('Failed!'));
}
}, 2000);
});
if (callback) {
p.then(d => {
callback(undefined, d);
}, e => {
callback(e);
});
}
return p;
}
Какой из них лучше или есть более стандартный и элегантный способ сделать это? Можем ли мы сделать это с помощью async/await?
@marcelotokarnia в случае успеха, когда ошибки нет, я передаю его как undefined, так как я предпочитаю его вместо null.
кроме того, второй подход немного лучше, потому что в первом иногда функция возвращает обещание, а иногда - null.
кроме того, во втором подходе я бы также использовал return callback внутри then, так что вы можете работать с цепочками обещаний.
Оооо, я понял, ваш первый параметр - это ошибка, а второй - значение :) ваш обратный вызов работает как для успеха, так и для ошибки ... Я понимаю ... имеет смысл :)
@marcelotokarnia да, чтобы проиллюстрировать это resolves/rejects случайным образом :)
Вторая версия избегает дублирования кода, поэтому она более СУХАЯ. Кроме этого, рекомендовать то или другое нечего.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


async function squareAsync1(val, callback) {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve(val * val);
}
else {
reject(new Error('Failed!'));
}
}, 2000);
});
if (callback) {
return p.then(d => {
return callback(undefined, d);
}, e => {
return callback(e);
});
}
return p;
}
Да, ваше решение будет работать с async / await. Обратите внимание, я только что добавил return в p.then
Таким образом вы можете сделать что-то вроде:
const x = await squareAsync1(2, (e, v) => e ? 1 : v * 2)
И вы получите x как 1 (если обещание было отклонено) или 8 (если обещание было успешным).
Сделать это можно так:
function squareAsync(val, callback) {
const timeout = function(res, rej){
setTimeout(function(){
if (Math.random() < 0.5)
res(val*val);
else
rej(new Error('Failed!'));
}, 2000);
}
return typeof callback === 'function'
? timeout(callback.bind(null, undefined), callback)
: new Promise(timeout);
}
// CALLBACK EXAMPLE
squareAsync(5, (err, val) => {
if (err)
console.info(`Callback: ${err}`);
else
console.info(`Callback: ${val}`);
})
// PROMISE EXAMPLE
squareAsync(5)
.then(val => console.info(`Promise: ${val}`))
.catch(err => console.info(`Promise: ${err}`))Объяснение
setTimeout в одну функцию-оболочку timeout, чтобы вам не приходилось повторять почти идентичный код.timeout принимает два аргумента: res и rej(разрешить и отклонить)timeout, если обратный вызов передан с функцией, иначе вернуть new Promise(timeout).Теперь о том, что происходит в:
return typeof callback === 'function'
? timeout(callback.bind(null, undefined), callback)
: new Promise(timeout);
Это переводится как:
if (typeof callback === 'function'){
// Bind `null` as `this` value to `callback
// and `undefined` as its first argument (because no error).
// Need to to this because in `timeout` function,
// we call `res` with only 1 argument (computed value) if success.
const resolve = callback.bind(null, undefined);
// Don't need to bind anything
// because the first argument should be error.
const reject = callback;
// Call the function as if we are in a Promise
return timeout(resolve, reject);
}
// Use `timeout` function as normal promise callback.
return new Promise(timeout);
Надеюсь, вы понимаете. Не стесняйтесь комментировать, если запутались.
Вы должны быть осторожны, чтобы поддерживать функции, которые будут возвращать разные типы в зависимости от параметров, как я прокомментировал исходный вопрос. В вашем примере вы можете выполнить цепочку обещаний, если вы не передаете обратный вызов, но вы не можете, если вы это сделаете. Это немного сложно поддерживать, особенно если ваш обратный вызов - переменная, возможно, не определенная. Я предлагаю вам вернуть обещанный автоматически решенный, даже если вы получите обратный звонок.
почему вы вызываете обратный вызов с неопределенным в качестве первого параметра?