我想知道是否有人知道promise链如何引用下一个错误处理程序 - 例如:
const p = new Promise(resolve => resolve(5))
.then(v => 5*v)
.then(v => { throw 'foo' });
p.then(v => v/4)
.then(v => v+3)
.catch(e => console.error('first catch:', e));
p.then(v => v/4)
.then(v => v+3)
.catch(e => console.error('second catch:', e));
如果你跑了,你会得到:
first catch: foo
second catch: foo
据我所知,每一次 Promise.prototype.then
是一个被调用的,创建并返回一个新的promise。我能想到能够找到的承诺的唯一方法 下一个错误处理器 对于每个链,都有一个对子项的引用数组。因此,如果承诺被拒绝,它将通过所有孩子并在每个子链中找到最接近的拒绝处理程序。
有谁知道这是如何实现的?
我看到它的方式:
将promises视为嵌套数组:
[then1,[then1.1, then1.2, catch1.1, then1.3, then1.4], then2, catch1]
看起来像这样:
new Promise(...)
.then(() => { // <- 1
return Promise(...)
.then() // <- 1.1
.then() // <- 1.2
.catch() // <- 1.1
.then() // <- 1.3
.then() // <- 1.4
})
.then() // <- 2
.catch() // <- 1
现在假设我们开始执行,它从最顶层的数组开始。我们为每个数组都有一个索引,指定我们在执行方面正在等待哪个元素。
我们先打电话来 .then1
,它本身返回一个promise链(另一个数组)。当出现错误时,层次结构数组中最低的(最深的) 跳过(不执行) 它是元素,直到找到一个 catch
。如果是,则执行 catch
并继续执行其他元素。如果没找到 catch
它要求父数组查找并执行a catch
,跳过所有元素 包括它的子数组,因为它们没有捕获。
在我们的示例中,如果发生错误 then1.2
它会被抓住 catch1.1
,但如果它发生在 then1.3
它会一直传播到 catch1
跳绳 then1.4
和 then2
编辑:
以下是要试验的代码:
new Promise(res => res())
.then(() =>
new Promise(res => res())
.then(() => console.log(1))
.then(() => {console.log(2); throw "Error 1"})
.catch((err) => console.log(err))
.then(() => {console.log(3); throw "Error 2"}))
.then(() => console.log(4))
.then(() =>
new Promise(res => res())
.then(() => console.log(6))
.then(() => {console.log(7); throw "Error 3"})
.catch((err) => console.log(err))
.then(() => console.log(8))
.then(() => {console.log(9); throw "Error 4"}))
.then(() => console.log(10))
.catch((err) => console.log(err))
它记录:
1
2
错误1
3
错误2
所以,让我们先介绍一下你的例子。
const p = new Promise(resolve => resolve(5))
.then(v => 5*v)
.then(v => { throw 'foo' });
p.then(v => v/4)
.then(v => v+3)
.catch(e => console.error('first catch:', e));
p.then(v => v/4)
.then(v => v+3)
.catch(e => console.error('second catch:', e));
在这里你实际上有3个不同的承诺:
p
是的 Promise.then.then
, anonymous
是的 p.then.then.catch
,和 anonymous
是的 p.then.then.catch
。
记住这一点 Promise.then
和 Promise.catch
返回包含之前Promise的Promises。所以你最终得到的是与这三个承诺链的嵌套承诺。
什么时候 p
最终投入评估的第三个承诺,其他两个承诺现在检查返回类型,标志和其他内部信息,最终导致他们实现从链中较早的承诺被拒绝,因此它必须拒绝。您还可以使用以下方法模拟此:
var p = Promise.reject(new Error('Hi from p!'))
p.catch(e => console.log('Hello from a different promise', p))
==
p.catch(e => console.log('Hello from a yet different promise', p))
您应该注意到评估的返回值为false,这意味着两个对象不相等。
现在如果我们稍等一下然后附加一个新的catch处理程序会发生什么 p
?
setTimeout(() => p.catch(console.log), 500)
您应该注意到另一个控制台日志,这次只有'Hi from p!'
原因是Promise评估的顺序。它评估创建,如果它是在被拒绝的promise上创建的,它会评估为拒绝并转到catch处理程序。
您认为以下是什么?
Promise
.reject(new Error('1'))
.catch(console.log)
.then(() => Promise.reject(new Error('2')))
.then(() => new Error('3'))
.then(console.log)
.catch(console.log)
.catch(() => console.log('4'))
这是正确的,你会看到打印错误('1'),然后是打印错误('2'),但不是打印错误('3')或打印'4'。那是因为a .catch
promise执行以下两项操作之一:解析对已解析值的承诺,或者在链被拒绝时解析对函数值的承诺。
相反 .then
只能解决一个承诺。如果它的分辨率被拒绝,它将以分辨率拒绝。
这有点令人困惑,但是一旦你意识到承诺会等待解决,并且会检查和链接承诺,你就会更容易找出你拒绝的地方。