作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在为运行 docker 堆栈和容器的 Node CLI 创建初稿。
每次调用都是使用 docker 命令进行的,具有异步调用和结果。所以我们决定使用 promise 。
我们现在的主要问题是著名的 then
级联,尤其是当我们必须沿途传递值并启动微调器/消息时。
这是我们主要的丑陋方法。我试图弄清楚如何重构它以使其更具...可读性!
upgradeServiceImage({env, stack, service}) {
if (!env || !stack || !service) {
throw Error(`You must specify env, stack and service to upgrade a service`);
}
let payloadSpinner = ora({
text: `Getting upgrade payload. Please wait...`
}).start();
this.getServiceUpgradePayload({env, stack, service})
.then((response) => {
payloadSpinner.succeed(`Upgrade payload retrieved successfuly for service ${stack} > ${service}`);
let upgradeSpinner = ora({
text: `Upgrading the service. Please wait...`
}).start();
this.upgradeImage(response)
.then((res) => {
upgradeSpinner.succeed(`Image upgrade request for service "${service}" was made.`);
this.checkUpgrade({env, stack, service}).then((res) => {
let finishUpgradeSpinner = ora({
text: `Finishing upgrade of service by deleting old container. Please wait...`
}).start();
this.finishUpgrade(response).then(() => {
finishUpgradeSpinner.succeed(`Upgrade is now complete!`);
})
.catch((err) => {
finishUpgradeSpinner.fail(`Finishing upgrade failed. Please see in UI. Err: ${err}`);
})
})
.catch((err) => {
upgradeSpinner.fail(`${err}`);
})
})
.catch((err) => {
upgradeSpinner.fail(`Image upgrade failed with error: ${err}`);
});
})
.catch((err) => {
payloadSpinner.fail(err);
});
};
它工作完美,但几乎不可读且模块化。
我尝试使用 Promise.all 进行一些修复,但我在正确恢复微调器(加载消息)时遇到了问题,而且我无法将对象从一个 promise 传递到另一个 promise (例如:response
) .
最佳答案
给定这样的代码:
let payloadSpinner = ora({
text:
}).start();
this.getServiceUpgradePayload({env, stack, service})
.then((response) => {
payloadSpinner.succeed(`Upgrade payload retrieved successfuly for service ${stack} > ${service}`);
// start the second task
})
.catch((err) => {
payloadSpinner.fail(err);
});
您可以使用为您管理微调器的助手重写它:
function withSpinner({ task, textOnStart, textOnSuccess, textOnError }) {
const spinner = ora({
text: textOnStart,
})
return task.then(value => {
spinner.succeed(textOnSuccess(value));
return result;
}, reason => {
spinner.fail(reason);
return Promise.reject(reason);
});
}
upgradeServiceImage({env, stack, service}) {
if (!env || !stack || !service) {
throw Error(`You must specify env, stack and service to upgrade a service`);
}
withSpinner({
task: this.getServiceUpgradePayload({env, stack, service}),
textOnStart: `Getting upgrade payload. Please wait...`,
textOnSuccess: result => `Upgrade payload retrieved successfuly for service ${stack} > ${service}`,
textOnError: error => error,
}).then(result => {
// start the second task
})
然后您可以重新使用帮助程序为后续步骤创建微调器。
请注意 withSpinner
返回的 promise 被拒绝,因此如果第一个任务失败,第二个任务将不会执行。
这是一个工作演示:
/* some scaffolding for the purpose of the example */
let spinnerId = 0;
function ora({ text }) {
let myId = spinnerId++;
console.log("Spinner", myId, "start", text);
return {
succeed(msg) {
console.log("Spinner", myId, "succeed", msg);
},
fail(msg) {
console.log("Spinner", myId, "fail", msg);
}
};
}
function delay(ms, result) {
return new Promise(resolve => setTimeout(() => resolve(result), ms));
}
function delayFail(ms, reason) {
return new Promise((resolve, reject) => setTimeout(() => reject(reason), ms));
}
/* scaffolding ends, actual code begins */
function withSpinner({ task, textOnStart, textOnSuccess, textOnError }) {
const spinner = ora({
text: textOnStart,
})
return task.then(value => {
spinner.succeed(textOnSuccess(value));
return value;
}, reason => {
spinner.fail(reason);
return Promise.reject(reason);
});
}
function upgradeServiceImage() {
return withSpinner({
task: delay(500, "THE UPGRADE PAYLOAD"),
textOnStart: `Getting upgrade payload. Please wait...`,
textOnSuccess: result => `Upgrade payload retrieved successfuly: ${result}`,
textOnError: error => error,
}).then(result => {
return withSpinner({
task: delay(800, "upgradeImage"),
textOnStart: `Upgrading the service. Please wait...`,
textOnSuccess: result => `Image upgrade request for service was made.`,
textOnError: error => error,
});
}).then(result => {
return withSpinner({
task: delayFail(700, "some kind of error"),
textOnStart: `Checking upgrade`,
textOnSuccess: result => `Checking upgrade finished`,
textOnError: error => `CHecking upgrade failed because ${error}`,
});
}).then(result => {
console.log("this won't run anymore because previous step failed");
}).catch(error => {
// additionally log the error if you want
console.error("catch", error);
});
};
upgradeServiceImage();
更新:这是使用 async/await 时相同代码的样子。只有 upgradeServiceImage 功能已被修改。这种方法更“扁平”和可读。这也使得在连续任务中使用以前的结果变得简单。
/* some scaffolding for the purpose of the example */
let spinnerId = 0;
function ora({ text }) {
let myId = spinnerId++;
console.log("Spinner", myId, "start", text);
return {
succeed(msg) {
console.log("Spinner", myId, "succeed", msg);
},
fail(msg) {
console.log("Spinner", myId, "fail", msg);
}
};
}
function delay(ms, result) {
return new Promise(resolve => setTimeout(() => resolve(result), ms));
}
function delayFail(ms, reason) {
return new Promise((resolve, reject) => setTimeout(() => reject(reason), ms));
}
/* scaffolding ends, actual code begins */
function withSpinner({ task, textOnStart, textOnSuccess, textOnError }) {
const spinner = ora({
text: textOnStart,
})
return task.then(value => {
spinner.succeed(textOnSuccess(value));
return value;
}, reason => {
spinner.fail(reason);
return Promise.reject(reason);
});
}
async function upgradeServiceImage() {
try {
const upgradeResult = await withSpinner({
task: delay(500, "THE UPGRADE PAYLOAD"),
textOnStart: `Getting upgrade payload. Please wait...`,
textOnSuccess: result => `Upgrade payload retrieved successfuly: ${result}`,
textOnError: error => error,
});
const upgradeImageResult = await withSpinner({
task: delay(800, "upgradeImage"),
textOnStart: `Upgrading the service. Please wait...`,
textOnSuccess: result => `Image upgrade request for service was made.`,
textOnError: error => error,
});
const anotherResult = await withSpinner({
task: delayFail(700, "some kind of error"),
textOnStart: `Checking upgrade`,
textOnSuccess: result => `Checking upgrade finished`,
textOnError: error => `CHecking upgrade failed because ${error}`,
});
console.log("this won't run anymore because previous step failed");
} catch (error) {
// additionally log the error if you want
console.error("catch", error);
};
};
upgradeServiceImage();
关于javascript - 用传递的结果重构 promise 级联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46073194/
我是一名优秀的程序员,十分优秀!