我是在正确地链接 Promise 还是犯了罪?
Am I chaining Promises correctly or committing a sin?
我已经很长时间没有使用 Javascript 了,所以现在 promises 对我来说是一个新概念。我有一些操作需要 多个异步调用 但我想将其视为一个事务,如果前面的步骤失败,则步骤不会执行。目前我通过嵌套链接承诺,我想return向调用者承诺。
阅读 Mozilla 的 Using Promises 指南的链接部分后,我不确定我所做的是否正确或等同于 "callback pyramid of doom"。
有没有更简洁的方法来做到这一点(除了在每个 then
中链接一个警卫检查)?我是否相信在 Mozilla 的示例中它会执行每个链式 then
即使出现错误?
myfunction(key) => {
return new Promise((outerResolve, outerReject) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}
}).then((resolve) => {
//Now the inner most item is resolved, we are working in the 'outer' shell
if (resolve.error) {
outerReject(resolve);
} else {
//No error, continue
new Promise((resolve, reject) => {
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}).then((resolve) => {
//finally return the result to the caller
if (resolve.error) {
outerReject(resolve);
} else {
outerResolve(resolve);
}
});
}
});
});
}
当抛出异常时,不会执行后续的 then
语句(直到 catch
)。此外,.then
returns 一个 Promise,因此您无需创建额外的外部 Promise。
试试这个例子:
var p = new Promise((resolve, reject) => {
console.log('first promise, resolves');
resolve();
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('then after the error');
return('result');
});
p.then(res => console.log('success: ' + res), err => console.log('error: ' + err));
您不会在控制台中看到 "then after the error",因为那是在抛出异常之后发生的。但是如果你注释 throw
语句,你将在 Promise 中得到你期望的结果。
我不确定我是否完全理解你的例子,但我认为它可以像这样简化:
myfunction(key) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: resolve(result);
});
}
}).then((previousData) => {
// keyBasedOnPreviousData is calculated based on previousData
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: return result;
});
});
}
有点乱。这是我重写的尝试。尽量避免的一件好事是 new Promise()
.
function chromeStorageGet(key) {
return new Promise( (res, rej) => {
chrome.storage.sync.get(key, result => {
if (chrome.runtime.lastError) {
rej(new Error(chrome.runtime.lastError.message))
} else {
res(result)
}
});
});
});
function myfunction(key) {
const item = cache.get(key) ? Promise.resolve(cache.get(key)) : chromeStorageGet(key);
return item.then( cacheResult => {
return chromeStorageGet(keyBasedOnPreviousData);
});
}
为什么要避免new Promise()
?
这样做的原因是您想用 then()
完成每一步。如果 any 的承诺中发生任何错误,链中的每个承诺都将失败,并且任何后续的 then()
都不会被执行 until有一个 catch()
处理程序。
许多承诺 based-code 不需要错误处理程序,因为 promise-based 函数总是 return 承诺和异常应该全部返回给调用者,直到有有用的事情要做错误处理。
请注意,这 2 条规则的例外情况在我的 chromeStorageGet
函数中。这里有几点说明:
new Promise
是一种将回调代码转换为承诺代码的快速简便的方法。
- 为此 callback-based 代码创建一个小的转换层通常是个好主意。如果您在其他地方需要
chrome.storage.sync
,也许可以创建一个小实用程序来实现其所有功能。
- 如果只有1个'flow',可以直接用一系列
then()
来完成,但有时需要有条件地做其他事情。只需将这些复杂的操作拆分为多个不同的函数就可以真正提供帮助。
但是这个:
const result = condition ? Promise.resolve() : Promise.reject();
几乎总是优先于:
const result = new Promise( (res, rej) => {
if (condition) {
res();
} else {
rej();
}
}
我已经很长时间没有使用 Javascript 了,所以现在 promises 对我来说是一个新概念。我有一些操作需要 多个异步调用 但我想将其视为一个事务,如果前面的步骤失败,则步骤不会执行。目前我通过嵌套链接承诺,我想return向调用者承诺。
阅读 Mozilla 的 Using Promises 指南的链接部分后,我不确定我所做的是否正确或等同于 "callback pyramid of doom"。
有没有更简洁的方法来做到这一点(除了在每个 then
中链接一个警卫检查)?我是否相信在 Mozilla 的示例中它会执行每个链式 then
即使出现错误?
myfunction(key) => {
return new Promise((outerResolve, outerReject) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}
}).then((resolve) => {
//Now the inner most item is resolved, we are working in the 'outer' shell
if (resolve.error) {
outerReject(resolve);
} else {
//No error, continue
new Promise((resolve, reject) => {
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}).then((resolve) => {
//finally return the result to the caller
if (resolve.error) {
outerReject(resolve);
} else {
outerResolve(resolve);
}
});
}
});
});
}
当抛出异常时,不会执行后续的 then
语句(直到 catch
)。此外,.then
returns 一个 Promise,因此您无需创建额外的外部 Promise。
试试这个例子:
var p = new Promise((resolve, reject) => {
console.log('first promise, resolves');
resolve();
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('then after the error');
return('result');
});
p.then(res => console.log('success: ' + res), err => console.log('error: ' + err));
您不会在控制台中看到 "then after the error",因为那是在抛出异常之后发生的。但是如果你注释 throw
语句,你将在 Promise 中得到你期望的结果。
我不确定我是否完全理解你的例子,但我认为它可以像这样简化:
myfunction(key) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: resolve(result);
});
}
}).then((previousData) => {
// keyBasedOnPreviousData is calculated based on previousData
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: return result;
});
});
}
有点乱。这是我重写的尝试。尽量避免的一件好事是 new Promise()
.
function chromeStorageGet(key) {
return new Promise( (res, rej) => {
chrome.storage.sync.get(key, result => {
if (chrome.runtime.lastError) {
rej(new Error(chrome.runtime.lastError.message))
} else {
res(result)
}
});
});
});
function myfunction(key) {
const item = cache.get(key) ? Promise.resolve(cache.get(key)) : chromeStorageGet(key);
return item.then( cacheResult => {
return chromeStorageGet(keyBasedOnPreviousData);
});
}
为什么要避免new Promise()
?
这样做的原因是您想用 then()
完成每一步。如果 any 的承诺中发生任何错误,链中的每个承诺都将失败,并且任何后续的 then()
都不会被执行 until有一个 catch()
处理程序。
许多承诺 based-code 不需要错误处理程序,因为 promise-based 函数总是 return 承诺和异常应该全部返回给调用者,直到有有用的事情要做错误处理。
请注意,这 2 条规则的例外情况在我的 chromeStorageGet
函数中。这里有几点说明:
new Promise
是一种将回调代码转换为承诺代码的快速简便的方法。- 为此 callback-based 代码创建一个小的转换层通常是个好主意。如果您在其他地方需要
chrome.storage.sync
,也许可以创建一个小实用程序来实现其所有功能。 - 如果只有1个'flow',可以直接用一系列
then()
来完成,但有时需要有条件地做其他事情。只需将这些复杂的操作拆分为多个不同的函数就可以真正提供帮助。
但是这个:
const result = condition ? Promise.resolve() : Promise.reject();
几乎总是优先于:
const result = new Promise( (res, rej) => {
if (condition) {
res();
} else {
rej();
}
}