简体   繁体   English

LONG:为什么如果我们从异步 function 返回 promise,它不会立即解决?

[英]LONG: Why if we return a promise from our async function, its not immediately resolved?

Apologies in advance if this is a dumb question, I've been trying to find the answer to my question for a good while now but still no luck and that's causing me not to progress further in my JS learning!如果这是一个愚蠢的问题,请提前道歉,我一直在努力寻找问题的答案,但仍然没有运气,这导致我在 JS 学习中没有进一步进步!

Q: Why even if we return a resolved promise from our async function, it's not immediately resolved?问:为什么即使我们从异步 function 返回已解决的 promise,它也没有立即解决?

Now MDN is teaching me this:现在 MDN 教我这个:

Async functions always return a promise.异步函数总是返回 promise。 If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.如果异步 function 的返回值不是显式 promise,它将隐式包装在 promise 中。

This means, both the functions below f1 and f2, are equivalent!这意味着,f1 和 f2 下面的函数是等价的!

async function f1(){
    
    return 100;
}
 
    async function f2(){
    
    return Promise.resolve(100);
}
    
    console.log(f1());
    console.log(f2());

However, we get different logs:但是,我们得到不同的日志:

One logs: Promise {: 100}一个日志:Promise {: 100}

Second logs: Promise pending第二条日志:Promise 待定

What's even more confusing is, when I expand the second promise's, even tho it says its pending, i see [[PromiseResult]]: 100.更令人困惑的是,当我扩展第二个承诺时,即使它说它的未决,我看到 [[PromiseResult]]: 100。

Now my naive programming experience suggests, only if a value (string, num, arr, obj etc) is returned from the async function, the promise our async function returns by default will be resolved to that value!现在我幼稚的编程经验表明,只有从异步 function 返回值(字符串、num、arr、obj 等)时,promise 我们的异步 ZC1C425268E68385D14AB5074C17A 默认返回的值将被解析为 4F14AB5074C17A

But if our async function returns a promise that we ourself made inside our async function, then the default promise that async function returns wont be returned, instead the promise we made inside our async function will be returned. But if our async function returns a promise that we ourself made inside our async function, then the default promise that async function returns wont be returned, instead the promise we made inside our async function will be returned.

But that raises another question, what if we have await in our function?但这提出了另一个问题,如果我们在 function 中有 await 怎么办? Await immediately returns a pending promise and whatever value we return from our async function is resolved with the promise our async function returns but again, what if we're returning a function? Await immediately returns a pending promise and whatever value we return from our async function is resolved with the promise our async function returns but again, what if we're returning a function?

A friend of mine told me if we are returning a resolved promise from our async function, some anonymous task is registered into the microtask queue which when run (after all the sync code,) unpacks the value from our the secondary promise and finally resolves our default promise returned by async function with that value and that seems to be working!我的一个朋友告诉我,如果我们从我们的异步 function 返回一个解析的 promise,一些匿名任务会注册到微任务队列中,当运行时(在所有同步代码之后),从我们的辅助 ZB321DE3BDC299DF9DEEBZE 解压缩值并最终解析 our异步 function 返回的默认 promise 具有该值,这似乎有效!

To test this assumption, I wrote this code:为了测试这个假设,我写了这段代码:

   let o = new Promise(function (r){
    r(100)
});

o.then(function first(){console.log(p)})
.then(function second(){console.log(p)})

async function f(){

return new Promise(function (r){
    r(100)
})
}

let p = f();

Our o promise is gonna be resolved immediately so our first.then cb will be pushed to the microtask queue, like this maybe!我们的 o promise 将立即得到解决,因此我们的 first.then cb 将被推送到微任务队列,可能像这样!

MICROTASK_QUEUE = [function first(){console.log(p)}] MICROTASK_QUEUE = [函数优先(){console.log(p)}]

On the next line we run f(), it goes inside f and sees we're returning a resolved promise so it returns a pending promise into p!在下一行我们运行 f(),它进入 f 并看到我们正在返回一个已解析的 promise,因此它将一个待处理的 promise 返回到 p!

Now our microtask is like this:现在我们的微任务是这样的:

MICROTASK_QUEUE = [function first(){console.log(p)}, someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue] MICROTASK_QUEUE = [function first(){console.log(p)}, someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue]

Our sync code is done, so we run our first task from microtask queue which happens to be our first.then, this one: function first(){console.log(p)}我们的同步代码完成了,所以我们从微任务队列运行我们的第一个任务,这恰好是我们的第一个。然后,这个:function first(){console.log(p)}

This one is run and as expected, prints pending, Since this returns nothing.这一个运行,如预期的那样,打印挂起,因为这不返回任何内容。 it returns undefined but since the promise's root,then is resolved.它返回未定义,但由于承诺的根,然后被解决。 now our microtask queue looks like this after registering another.then.现在我们的微任务队列在注册 another.then 后看起来像这样。

MICROTASK_QUEUE = [someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue, function second(){console.log(p)}] MICROTASK_QUEUE = [someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue, function second(){console.log(p)}]

Now, this function is run someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue() (maybe internally unlike our.then functions)现在,这个 function 正在运行 someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue() (可能在内部与 our.then 函数不同)

now at this point promise that was earlier returned by our async function should be resolved with the value we resolved in our custom-made function, correct?现在此时由我们的异步 function 返回的 promise 应该使用我们在定制的 function 中解析的值来解析,对吗?

Now finally event loop checks the microtask queue and finds the final function to run, this one:现在最后事件循环检查微任务队列,找到最终的 function 运行,这个:

function second(){console.log(p)} function second(){console.log(p)}

now why does this still return a pending promise?现在为什么这仍然返回一个未决的 promise?

I think there's still one more step I'm missing in this whole equation because if I put the 3rd.then, it finally logs this "Promise {: 100}" which is what I'm after!我认为在整个等式中我还缺少一步,因为如果我把第 3 个放在后面,它最终会记录这个“Promise {: 100}”,这就是我所追求的!

let o = new Promise(function (r){
    r(100)
});

o.then(x => console.log(p))
.then(x => console.log(p))
.then(x => console.log(p))
async function f(){

return new Promise(function (r){
    r(100)
})
}

let p = f();

I'm thankful to you if you read this far and it'd be greatly appreciated if someone could answe this如果你读到这里,我很感激你,如果有人能回答这个问题,我将不胜感激

You should ignore the exact timing and ordering of the microtask jobs, it is not relevant for writing code - if you have dependencies between sections of asynchronous code, make them explicit, do not rely on queuing.您应该忽略微任务作业的确切时间和顺序,这与编写代码无关 - 如果您在异步代码部分之间存在依赖关系,请将它们明确化,不要依赖排队。

But it's fun to look at the internals of the JS engine anyway, so…但无论如何,看看 JS 引擎的内部结构还是很有趣的,所以……

But if our async function returns a promise that we ourself made inside our async function, then the default promise that async function returns wont be returned, instead the promise we made inside our async function will be returned. But if our async function returns a promise that we ourself made inside our async function, then the default promise that async function returns wont be returned, instead the promise we made inside our async function will be returned.

No, that's not what happens.不,这不是发生的事情。 Your doubt about await followed by a returned promise brought you back on track - it always resolves the default promise with the return value, whatever that value is and whenever the return evaluates (immediately vs. asynchronously).您对await的疑问,然后是返回的 promise 让您回到正轨 - 它总是return值解析默认的 promise,无论该值是什么以及无论何时return评估(立即与异步)。 Your friend is right.你的朋友是对的。

Now, this function is run: someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue() (maybe internally unlike our.then functions)现在,运行此 function: someTaskThatWillUnpackOurPromiseAndResolveOurPromiseReturnedByTheAsyncFunctionByThatValue() (可能在内部与 our.then 函数不同)

now at this point promise that was earlier returned by our async function should be resolved with the value we resolved in our custom-made function, correct?现在此时由我们的异步 function 返回的 promise 应该使用我们在定制的 function 中解析的值来解析,对吗?

Not quite.不完全的。 You assumed that this unpacking happens unlike our .then() functions.您假设这种解包与我们的.then()函数不同。 But this is a potential optimisation that ES6 did fail to specify.但这是 ES6 未能指定的潜在优化。 Instead, it happens exactly like calling the .then() method - and not just "like": it indeed just does call the .then() method, which is necessary to resolve ordinary thenables, without taking a look whether the target is a native promise or a thenable.相反,它的发生与调用.then()方法完全一样——而不仅仅是“like”:它确实只是调用了.then()方法,这是解析普通 thenable 所必需的,而没有查看目标是否是本机 promise 或 thenable。

And what the invoked .then(resolve, reject) method does is to schedule yet another job with the callback, which causes the outer promise to be resolved only after one additional tick.调用的.then(resolve, reject)方法所做的是使用回调安排另一个作业,这会导致外部 promise 仅在一个额外的滴答后才被解析。

You can compare the timings between the following functions:您可以比较以下函数之间的时间:

const fulfilled = Promise.resolve('a');
async function a() {
  return {
    then(onFulfillment, onRejection) {
      console.log('promise then');
      fulfilled.then(onFulfillment, onRejection);
    }
  };
}
async function b() {
  return {
    then(onFulfillment, onRejection) {
      console.log('immediate then');
      onFulfillment('b');
    }
  };
}

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

相关问题 潜在的异步函数会返回一个立即解析的承诺吗? - Potentially async function return a promise that immediately resolves? 如何在function中返回从promise解析出来的值? - How to return the value resolved from promise in function? JavaScript异步函数,当没有返回值的情况下,返回时应答应解决 - JavaScript async function, when is returned promise resolved in the case of no return value 解决承诺后,异步功能将不会返回 - Async function won't return when the promise is resolved 立即使用AngularJS返回已解决的承诺 - Immediately return a resolved promise using AngularJS 异步功能何时会解决? - When is async function promise resolved? 是否可以在没有 async/await 的情况下从 promise 返回已解析的值? - Is it possible to return resolved value from promise without async/await? 为什么异步函数在等待已解决的承诺时返回? - Why async function returns on awaiting for already resolved promise? 为什么异步和等待未在函数外部返回已解决的承诺? - Why does async and await not returned a resolved promise outside of the function? javascript“await”是否会立即暂停它正在执行的操作并在承诺解决后恢复异步功能? - Does javascript "await" pauses immediately whatever it is doing and resumes the async function once a promise is resolved?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM