Reputation: 2235
let textProcess = new Promise((resolve, reject) => {
let text
try {
// fetch text from the internet
text = "str"
resolve(text)
} catch (e) {
reject("failed to fetch!")
}
})
textProcess.then(data => {
let json
try {
json = JSON.parse(data)
} catch (e) {
console.error("failed to parse!")
// ..........i want to end the whole process here, never go ahead
}
}, e => {
// try to fetch text from local chache
}).then(json => {
// work on the json obj
}, e => {
// if failed to fetch from local too, just let it go
})
Is there a way to end a thenable chain?
Look at the example above, I want to end the whole process when parsing is failed(the line preceeded with ".........."). But actually the last then will still be invoked though.
What is the proper and elegant way to achieve my goal?
Upvotes: 1
Views: 102
Reputation: 19301
The short answer is no, there is no mechanism to terminate a promise chain in a then
handler part-way down the chain. (A proposal for promise cancellation was made to the TC39 committee in 2016 but was subsequently withdrawn.)
Note that a "promise chain" often refers to the promise
returned by the last then
, catch
or finally
call in a chain of single promise method calls concatenated together.
All calls to the promise methods listed above are made synchronously when code defining the chain is executed. After execution, all promises in the chain have been created and all method calls in the chain called.
Since promises only have three states (pending, fulfilled and rejected), the best you can do is to arrange for "cancellation" to be sent down the rejection channel of linked promises and ignore it as required. (There is no standard "cancelled" rejection value to use).
Upvotes: 0
Reputation: 5220
Your Promise usage involves quite a bit of sub-optimal patterns. Fixing them actually leads to what you're trying to achieve too.
textProcess.then(data => {
// 1st anti-pattern fix
// any error triggered here
// also gets caught at the end catch
return JSON.parse(data)
}).then(json => {
// work on json obj
}).catch(e => {
// 2nd anti-pattern fix
// one catch for the whole thenable chain
console.error("Failed to parse!", e)
})
This way, you properly leverage what Javascript Promise offers, and one simple .catch
for what you need.
Edit - some explanations on involved Promise anti-patterns
The marked 1st anti-pattern
is about unnecessary nested try..catch
block within then
. Within it, you can return synchronously (even undefined
), another Promise (both of these are thenable
), or throw an Error (which would get caught by catch
). Basically you don't need to explicitly catch it but let it "flow" through.
The 2nd anti-pattern
as mentioned is the fact that the second parameter -- reject handler of then
is considered sub-optimal in most use cases. A Promise chain should be leveraging one catch
to simplify the workflow.
However, in the rare event of the need to perform "early catch" and "resume", consider the following way, which is still a bit clearer than using two handlers for then
:
textProcess.then(data => {
return parser1(data)
}).catch(e => {
console.log("First parser failed")
// for example first parser failed
return "fallback data"
}).then(data => {
// process received data as "fallback data"
}).catch(e => {
// always have a "last resort" catch at the end of the workflow
})
Upvotes: 1