简体   繁体   English

promise链如何引用下一个错误处理程序

[英]How promise chains reference the next error handler

I am wondering if anyone knows how promise chains reference the next error handler - for example: 我想知道是否有人知道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));

If you run that you will get: 如果你跑了,你会得到:

first catch: foo
second catch: foo

to my knowledge, every time Promise.prototype.then is a called, a new promise is created and returned. 据我所知,每次Promise.prototype.then被调用时,都会创建并返回一个新的promise。 The only way I can think of for the promise to be able to find the next error handler for each chain, is to have an array of references to the children. 我能想到能够为每个链找到下一个错误处理程序的承诺的唯一方法是拥有一个对子项的引用数组。 So if a Promise is rejected, it would go through all the children and find the closest rejection handlers in each child chain. 因此,如果承诺被拒绝,它将通过所有孩子并在每个子链中找到最接近的拒绝处理程序。

Does anyone know how this is implemented? 有谁知道这是如何实现的?

The way I see it: 我看待它的方式:

Think of promises as nested arrays: 将promises视为嵌套数组:

[then1,[then1.1, then1.2, catch1.1, then1.3, then1.4], then2, catch1]

looks like this: 看起来像这样:

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

Now imagine we start execution and it begins in the topmost array. 现在假设我们开始执行,它从最顶层的数组开始。 We have an index for each array specifying which element we are waiting for in terms of execution. 我们为每个数组都有一个索引,指定我们在执行方面正在等待哪个元素。 We start off by calling .then1 , which itself returns a promise chain (another array). 我们首先调用.then1 ,它本身返回一个promise链(另一个数组)。 When an error occurs your lowest in hierarchy array (the deepest one) skips through (doesn't execute) it's elements until it finds a catch . 当发生错误时,层次结构中最低的数组(最深的一个) 跳过(不执行)它的元素,直到它找到一个catch If it does, it executes the catch and continues executing the other elements. 如果是,则执行catch并继续执行其他元素。 If it doesn't find a catch it asks the parent array to find and execute a catch , skipping all elements including its children arrays because they are not catch . 如果找不到catch它会要求父数组查找并执行catch ,跳过所有元素, 包括子数组,因为它们没有捕获

In our example if an error occurs in then1.2 it will be caught by catch1.1 , but if it occurs in then1.3 it will propagate all the way to catch1 skipping then1.4 and then2 在我们的例子中,如果在then1.2发生错误,它将被catch1.1捕获,但如果它在then1.3发生, then1.3一直传播到catch1跳过then1.4然后then2

Edit: 编辑:

Here is code to experiment with: 以下是要试验的代码:

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))

it logs: 它记录:

1 1

2 2

Error 1 错误1

3 3

Error 2 错误2

So let's just step through your example first. 所以,让我们先介绍一下你的例子吧。

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));

Here you actually have 3 different promises: 在这里你实际上有3个不同的承诺:

p which is Promise.then.then , anonymous which is p.then.then.catch , and anonymous which is p.then.then.catch . pPromise.then.thenanonymousp.then.then.catchanonymousp.then.then.catch

Remember that Promise.then and Promise.catch return Promises that encompass the Promise from before. 请记住, Promise.thenPromise.catch返回包含之前Promise的Promises。 So what you're really ending up with is nested promises with those three promise chains. 所以你最终得到的是与这三个承诺链的嵌套承诺。

When p eventually throws in the third promise at evaluation the other two promises are now checking the return type, flags, and other internal information that eventually leads to them realizing a promise from earlier in the chain rejected and thus it must reject too. p最终在评估中抛出第三个承诺时,另外两个承诺现在正在检查返回类型,标志和其他内部信息,这些信息最终导致他们实现了链中较早的承诺被拒绝,因此它也必须拒绝。 You can also emulate this with the following: 您还可以使用以下方法模拟此操作:

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))

You should notice that the return of the evaluation is false which means the two objects aren't equal. 您应该注意到评估的返回值为false,这意味着两个对象不相等。

Now what happens if we wait a bit and then attach a new catch handler to p ? 现在如果我们等一下然后将一个新的catch处理程序附加到p什么?

setTimeout(() => p.catch(console.log), 500)

You should notice another console log, this time with only 'Hi from p!' 您应该注意到另一个控制台日志,这次只有'Hi from p!'

And the reason is order at which a Promise evaluates. 原因是Promise评估的顺序。 It evaluates on creation and if it's created on a rejected promise, it evaluates to rejected and goes to the catch handler. 它评估创建,如果它是在被拒绝的promise上创建的,它会评估为拒绝并转到catch处理程序。

What do you think you'll get with the following? 您认为以下是什么?

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'))

That's right you'll see a printed Error('1'), then a printed Error('2'), but not a printed Error('3') or a printed '4'. 这是正确的,你会看到打印错误('1'),然后是打印错误('2'),但不是打印错误('3')或打印'4'。 That's because a .catch promise does one of two things: resolves the promise to the resolved value, or resolves the promise to the functions value if the chain is rejected. 这是因为.catch承诺执行以下两项操作之一:解析对已解析值的承诺,或者在链被拒绝时解析对函数值的承诺。

In contrast .then only resolves a promise. 相反.then只解决了一个承诺。 If it's resolution is rejected, it rejects with the resolution. 如果它的分辨率被拒绝,它将拒绝解决方案。

It's a little confusing yes, but once you realize that promise will wait for resolution and will check and chaining promises it becomes a little easier to figure out where you'll reject to. 这有点令人困惑,但是一旦你意识到承诺会等待解决,并且会检查和链接承诺,你就会更容易找出你拒绝的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM