我怎样才能重写这些JavaScript承诺,使其不那么复杂?



我写了这个,但它看起来很粗糙,它适用于节点 js,所以所有值都需要按顺序获取

import tripfind from '../model/tripfind';
import addbook from '../model/addbook';
import bookfind from '../model/bookfind';
function addBook(info) {
return new Promise((resolve, reject) => {
let rowcount = -1;
bookfind(0, -1, -1).then((result) => {
if (result) {
rowcount = result.rowCount;
} else {
rowcount = 0;
}
tripfind(info.trip_id, 0).then((xresult) => {
let val = '';
if (xresult === 'false') {
val = 'trip is not valid';
resolve(val);
} else {
addbook(info, rowcount).then((value) => {
if (value === 'invalid id') {
resolve('invalid id');
}
resolve(value);
}).catch((err) => {
if (err) {
reject(err);
}
});
}
}).catch((error) => {
reject(error);
});
}).catch((err) => {
if (err) {
reject(err);
}
});
});
}
export default addBook;

这就是上面的代码,代码也会被导出并作为 promise 函数处理,如果可以,请提供帮助

不使用async/await,此示例在功能上等效于您之前的示例:

function addBook (info) {
return bookfind(0, -1, -1).then(result => {
const { rowCount } = result || { rowCount: 0 };
return tripfind(info.trip_id, 0).then(trip =>
trip === 'false'
? 'trip is not valid'
: addbook(info, rowCount)
);
});
}

像这样的部分

.then((value) => {
if (value === 'invalid id') {
resolve('invalid id');
}
resolve(value);
})
.catch((err) => {
if (err) {
reject(err);
}
});
.catch((error) => {
reject(error);
});

完全是多余的,因此删除它们根本不影响逻辑。删除这些并解开Promise构造函数反模式后,您可以看到逻辑变得更加简化。

你错过了一些return的承诺,如果你喜欢这种写作方式,你应该以同样的方式缩进then()catch()。也这样做

.catch((err) => {
if (err) {
reject(err);
}
});

没用的,因为你抓住一个错误来拒绝它。以promise模式重写(并进行一些优化):

function addBook(info) {
return bookfind(0, -1, -1)
.then((result) => {
rowcount = result ? result.rowCount : 0
return tripfind(info.trip_id, 0)
.then((xresult) => {
if (xresult === 'false') {
return 'trip is not valid'
}
return addbook(info, rowcount)
})
})
}

无论如何,异步/等待模式更清楚:

async function addBook(info) {
let result = await bookfind(0, -1, -1)
rowcount = result ? result.rowCount : 0
let xresult = await tripfind(info.trip_id, 0)
if (xresult === 'false')
return 'trip is not valid'
let value = await addbook(info, rowcount)
return value
}

像这样吗?

function addBook(info) {
return bookfind(0, -1, -1).then((result) => tripfind(info.trip_id, 0)
.then((xresult) => (xresult === 'false') ? 
'trip is not valid' : 
addbook(info, result ? result.rowCount : 0)
)
);
}

或与async/await

async function addBook(info) {
const result = await bookfind(0, -1, -1);
const xresult = await tripfind(info.trip_id, 0)
return xresult === "false"? 
'trip is not valid' : 
addbook(info, result ? result.rowCount : 0);
}

避免承诺/延迟反模式:什么是显式承诺构造反模式,如何避免它?

并删除无意义/无用的代码,例如以下函数:

(value) => {
if (value === 'invalid id') {
resolve('invalid id');
}
resolve(value);
}

它总是解析为value. 这就像return value === 1? 1: value

或者所有(error) => { reject(error); }只是将错误"转发"到返回的承诺。

或此结构

let rowcount = -1;
//....
if (result) {
rowcount = result.rowCount;
} else {
rowcount = 0;
}
//....
doSomethingWith(rowcount)

可以概括为doSomethingWith(result ? result.rowCount : 0)

很多人可能会告诉你,async/await会更好地解决这个问题。我认为问题更多的是关于如何使用承诺。如果您有权更改您正在调用的函数,这就是我的建议。

  1. 让函数返回相同形状的东西 - 例如,对bookfind的调用可以返回拒绝的承诺或包装undefined{..., :rowcount:12}的已解决承诺。如果我们删除undefined结果并返回默认{..., rowcount:0 }它将大大简化调用函数并更好地包含逻辑。

  2. 删除多余的函数调用(.catchs 和addbook.then位)

以下是这些功能的外观(根本不了解您的设置)

function tripfind(id, num) {
return new Promise(function(resolve, reject) {
doSomething(function(err, results) {
if (err) return reject(err);
if (results === "false") return reject(new Error("trip is not valid"));
return resolve(results);
});
});
}
function bookfind(id, start, end /*or whatever*/) {
return new Promise(function(resolve, reject) {
findBooks(function(err, results) {
if (err) return reject(err);
// handle odd cases too
if (!results) return resolve({ rowcount: 0 });
return resolve(results);
});
});
}

和用法

bookfind(0, -1, -1).then(results =>{}).catch(err=>{})
tripfind(id, 0).then(results =>{}).catch(err=>{})

以这种方式使用承诺,我们不必检查results的值,因为如果它不存在,承诺就不应该解析。同样,从承诺中产生的事物的形状应该始终相同。(当函数返回String|Object|Undefined时,我称之为气味,这是可能的,但我会先仔细研究它)

使用此模式并删除不执行任何操作的调用(所有.catch调用),我们可以将代码简化为:

function addBook(info) {
return bookfind(0, -1, -1).then(({ rowcount }) =>
tripfind(info.trip_id, 0).then(() =>
addbook(info, rowcount)
)
);
}

最新更新