我正在尝试使用promises编写一段代码,避免嵌套它们但我仍然在测试返回的结果来处理promises流程。 这种模式是否可行?
//一组承诺任务返回值
function doTask1() => {
return apiPromise1()
.then((result1) => {
return result1;
})
}
function doTask2(result1, paramOne) => {
return apiPromise2(result1, paramOne)
.then((result2) => {
return result2;
})
}
function doTask3(result1) => {
return apiPromise3()
.then((result3) => {
return result3;
})
}
function doTask4(result1, paramOne) => {
return apiPromise4()
.then((result4) => {
return result4;
})
}
//根据承诺返回结果处理承诺流程的主要承诺
function getCurrentProcess(paramOne) {
const promises = [];
// how to get the returned result1 to be used by other promises ?
promises.push(doTask1);
if (result1 === 'OK') {
promises.push(doTask2(result1, paramOne));
if (result2 === 'OK') {
promises.push(doTask3(result1));
if (result3 === 'OK') {
promises.push(doTask4(result1, paramOne));
}
}
}
return Promisz.all(promises)
.then(() => {
return 'well done'
});
}
//初始调用功能
exports.newJob = functions.https.onRequest((req, res) => {
const paramOne = { ... }
getCurrentProcess(paramOne).then((res) => {
return { status: 200, infos: res };
}, error => {
return {status: error.status, infos: error.message};
}).then(response => {
return res.send(response);
}).catch(console.error);
});
答案 0 :(得分:1)
如果您想以更多程序方式编写承诺,则需要使用async/await(ES6)。如果您需要向后兼容ES5,则需要使用将await / async转换为ES5的babel或typescript。
async function getCurrentProcess(paramOne) {
const result1 = await doTask1();
if (result1 === 'OK') {
const result2 = await doTask2(result1, paramOne);
if (result2 === 'OK') {
const result3 = await doTask3(result1);
if (result3 === 'OK') {
await doTask4(result1, paramOne);
}
}
}
return 'well done'
}
如果没有async / await,您需要使用promise chain:
doTask1().then((result1)=>{
if (result1 === 'OK') {
...
}
...
})
然而,它不会产生可读代码。
答案 1 :(得分:0)
如果你希望你的promise返回结果被其他promises使用,你不应该使用Promise.all()
方法,因为它不按你想要的顺序运行方法,它只是等待所有的promise方法完成并返回所有结果。
像promise-array-runner这样的东西会有帮助吗?
也许您可以检查任务方法中是否result === 'OK'
?或者创建一个Factory
来处理这个问题。
答案 2 :(得分:0)
您可以编写一个包装函数,该函数将doTaskN
数组作为延迟函数:
const conditional = (...fns) => {
if(fns.length === 0) return Promise.resolve();
const [next] = fns;
return next()
.then(() => conditional(...fns.slice(1)));
};
我们的想法是传递对doTask
函数的引用,以便conditional
函数执行它们。这可以像:
conditional(doTask1, doTask2, doTask3, doTask4)
.then(() => {
console.log("all done");
})
.catch(() => {
console.log("failed");
});
以下是如何使用它的完整示例:
const conditional = (...fns) => {
if(fns.length === 0) return Promise.resolve();
const [next] = fns;
return next()
.then(result => {
console.log("task:", result);
if(result === "OK") {
return conditional(...fns.slice(1))
}
});
};
const task1 = (param1, param2) => Promise.resolve("OK");
const task2 = (param1) => Promise.resolve("OK");
const task3 = () => Promise.resolve("failed");
const task4 = () => Promise.resolve("OK");
conditional(() => task1("one", 2), () => task2(1), task3, task4)
.then(() => {
console.log("all done");
})
.catch(() => {
console.log("failed");
});
答案 3 :(得分:0)
.then((result1) => {
return result1;
})
是一个无操作,应该省略,但我认为真正的代码没有这个问题。
这是async
函数的一个用例,因为它们可以无缝地处理这种控制流,正如另一个答案所暗示的那样。但由于async
是原始承诺的语法糖,因此可以用ES6编写。由于任务取决于彼此的结果,因此无法使用Promise.all
处理它们。
您可以通过抛出异常来避免承诺链,并避免使用以下嵌套条件:
// should be additionally handled if the code is transpiled to ES5
class NoResultError extends Error {}
function getCurrentProcess(paramOne) {
doTask1()
.then(result1 => {
if (result1 !== 'OK') throw new NoResultError(1);
return result1;
})
.then(result1 => ({ result1, result2: doTask2(result1, paramOne) }))
.then(({ result1, result2 }) => {
if (result2 !== 'OK') throw new NoResultError(2);
return result1;
})
// etc
.then(() => {
return 'well done';
})
.catch(err => {
if (err instanceof NoResultError) return 'no result';
throw err;
})
}
由于result1
用于多个then
回调,因此可以将其保存到变量中,而不是通过promise链传递。
如果在任务函数中抛出NoResultError
,则Promise链可能变得更简单。
答案 4 :(得分:0)
感谢所有反馈!!
所有答案都是权利......但是我投票支持CodingIntrigue wtapprer功能解决方案......
1 - 当我使用Firebase功能时,它仍然是ES5,我不能使用sync / await。仅对Firebase函数使用babel或typescript将导致更多的设置工作...
2 - 我测试了各种用例,这个模式很容易用JS级别来理解......我觉得以后可以改进...
所以我终于开始了......
let auth = null;
let myList = null;
const conditional = (...fns) => {
if(fns.length === 0) return Promise.resolve();
const [next] = fns;
return next()
.then(result => {
if(result) {
return conditional(...fns.slice(1));
}
return result;
});
};
const task1 = (param1) => Promise.resolve()
.then(() => {
console.log('TASK1 executed with params: ', param1)
auth = "authObject"
return true;
});
const task2 = (param1, param2) => Promise.resolve()
.then(() => {
console.log('TASK2 executed with params: ', param1, param2)
return true;
});
const task3 = (param1, param2) => Promise.resolve()
.then(() => {
console.log('TASK3 executed with params: ', param1, param2)
myList = "myListObject"
console.log('search for param2 in myList...')
console.log('param2 is NOT in myList task4 will not be executed')
return false;
});
const task4 = (param1) => Promise.resolve()
.then(() => {
console.log('TASK4 executed with params: ', param1)
return true;
});
// FIREBASE HTTP FUNCTIONS ==================
exports.newContactMessage = functions.https.onRequest((req, res) => {
conditional(() => task1("senderObject"), () => task2(auth, "senderObject"), () => task3(auth, "senderObject"), () => task4("senderObject"))
.then((res) => {
return { status: 200, infos: res };
}, error => {
return {status: error.status, infos: error.message};
}).then(response => {
return res.send(response);
}).catch(console.error);
});