难以理解 Promise 的工作原理

发布于 2025-01-17 03:29:48 字数 967 浏览 8 评论 0原文

我有一段代码,可以从本地磁盘获取 JSON 文件:

var modelData = fetch("./modelData.json")
       .then((res) => res.json())
       .then((val) => console.log(val)

这样做我可以在浏览器控制台中完美地看到 JSON 数据。但是,当我这样做时:

    var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => val)
console.log(modelData)

我在控制台中看到一个 promise(pending) 。我知道异步 JS 是如何工作的,并且我知道链式 then() 仅在前一个承诺得到解决时才会触发。我的问题是,在我的第二个 then() 块中,为什么当我 console.log() 时可以看到数据,但当我从 console.logging 的同一函数返回它时看不到日期?

另外,如果我考虑到这样一个事实,即在第二种情况下,当我 console.logged 时,由于 fetch() 的异步性质,承诺没有得到履行,我尝试了以下操作:

var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => val)
setTimeout(()=>console.log(modelData), 1000)

认为一旦承诺得到履行,我肯定会得到我的价值。但后来我明白了

承诺(兑现)

。谁能告诉我我错过了什么?我将非常感谢任何帮助。

I have a piece of code where I fetch a JSON file from my local disk:

var modelData = fetch("./modelData.json")
       .then((res) => res.json())
       .then((val) => console.log(val)

And doing this I can perfectly see the JSON data in my browser console. However when I do this:

    var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => val)
console.log(modelData)

I see a promise(pending) in my console. I know how async JS works, and I know that the chained then() fires only when the previous promise is resolved. My question is, in my second then() block, why can I see the data when I console.log() it but cant see the date when I return it from the same function where I was console.logging it?

Also, if I consider the fact that maybe in the second case the promise wasnt fulfilled when I console.logged it, due to the async nature of fetch(), I tried the following:

var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => val)
setTimeout(()=>console.log(modelData), 1000)

thinking that once the promise is fulfilled, I will surely get my value. But then I get

Promise(fulfilled)

. Can anyone tell me what I am missing? I will be really grateful for any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

友谊不毕业 2025-01-24 03:29:48

一开始理解这个概念很困难。我将稍微更改您的代码:

var promise = fetch("./modelData.json");
promise.then((res) => res.json())
    .then((val) => console.log(val);
console.log(modelData)

如您所见,是相同的代码。我做出承诺并设定决心后要做的事情。您得到的是一个对象(承诺),它将运行您的提取,并在成功时调用您的“then”函数。

但变量“promise”(问题中的 modelData)始终是一个承诺。从来没有关于您的模型的数据。

想象一下,您调用某个延迟 60 秒的 setTimeout 函数,而不是 fetch。你的 console.log 将立即执行,在那一刻你不可能得到你的函数的结果,除了对象是一个承诺,而不是你获取的数据。
但是调试代码,想象一下你输入了promise代码,60秒后,你进入了“then”函数。在该函数内部,您可以获取数据。为此,您可以在 then 函数内部处理结果,而不是在外部。

It's difficult at first understanding this concepts. I'm going to change a bit your code:

var promise = fetch("./modelData.json");
promise.then((res) => res.json())
    .then((val) => console.log(val);
console.log(modelData)

As you see, is the same code. I create a promise and set what I want to do when become resolved. That you get is an object (the promise) that will run your fetch and, on success, will invoke your "then" funcion.

But the variable "promise" (modelData in your question) is always a promise. Never has data about your model.

Imagine that instead of fetch, you invoke some setTimeout function with 60 seconds of delay. Your console.log is going to be exectuted inmediatly and it's impossible that in that moment you have the results of your funcion, apart from that the objct is a promise, not your fetched data.
But debug the code, imagine that you enter into the promise code and after 60 seconds, you enter in the "then" function. Inside that function is where you have available your data. It's for that what you work with the results inside the then function, never outside.

柳絮泡泡 2025-01-24 03:29:48

你无法“拆开” Promise,但你甚至不必这样做。

Promise 并不是真实数据的占位符,一旦数据到达就会神奇地变成它。它是一个句柄,通过它您可以以相同的方式访问数据,无论数据是已经到达还是稍后到达。

因此,从 then 回调返回的任何内容都将始终包装在另一个 Promise 中,因此仍然无法从外部直接访问它。

如果我们有以下代码,

//`Promise.resolve` is added just for the sake of illustration (it wraps its argument in a promise similarly to what `then` does)
const p1 = Promise.resolve(fetch("./modelData.json"))
const p2 = p1.then((res) => res.json())
const p3 = p2.then((val) => val)

...我们可以像这样可视化结构:

        Promise.resolve(  fetch(...)  )
        vvvvvvvvvvvvvvv   vvvvvvvvvv
 +------+++++++++++++++   ++++++++++
 |                         |
 v                        vvv
p1 ---------------- .then(res => res.json())
                     vvvv        vvvvvvvvvv
 +-------------------++++        ++++++++++
 |                         +-----+
 |                         |
 v                        vvv
p2 ---------------- .then(val => val)
                     vvvv        vvv
 +-------------------++++        +++
 |                         +------+
 |                         |
 v                         v
p3  • • • • • • • • .then(... => ...)

正如您所看到的,需要另一个 .then 来访问 p3

这就是为什么console.log内部then可以打印真实值,而console.log在外部只会给你一个承诺。

You can't "unwrap" a Promise, but you shouldn't even have to.

A Promise is not a placeholder for the real data that will magically turn into it once it arrives. It's a handle, through which you can access the data the same way no matter if it has already arrived or will only arrive later.

For that reason, anything returned from a then callback will always be wrapped in another promise, so that it's still not possible to directly access it from the outside.

If we have the following code,

//`Promise.resolve` is added just for the sake of illustration (it wraps its argument in a promise similarly to what `then` does)
const p1 = Promise.resolve(fetch("./modelData.json"))
const p2 = p1.then((res) => res.json())
const p3 = p2.then((val) => val)

...we can visualise the structure like this:

        Promise.resolve(  fetch(...)  )
        vvvvvvvvvvvvvvv   vvvvvvvvvv
 +------+++++++++++++++   ++++++++++
 |                         |
 v                        vvv
p1 ---------------- .then(res => res.json())
                     vvvv        vvvvvvvvvv
 +-------------------++++        ++++++++++
 |                         +-----+
 |                         |
 v                        vvv
p2 ---------------- .then(val => val)
                     vvvv        vvv
 +-------------------++++        +++
 |                         +------+
 |                         |
 v                         v
p3  • • • • • • • • .then(... => ...)

As you can see from that, another .then would be required to access the value in p3.

That is why console.logging inside a then can print the real value, while console.logging outside will only give you a promise.

请你别敷衍 2025-01-24 03:29:48

fetch() 函数和 then() 方法都返回一个 Promise 对象。您将该 Promise 对象分配给 modelData,它将保留为 Promise 对象,并且不会自动重新分配给已实现的值。

要获取已完成的值,您可以使用 then() 方法或 await 关键字

// name it `modelPromise` to be clear
const modelPromise = fetch("./modelData.json")
           .then(res => res.json())
           .then(val => val)

modelPromise.then(val => console.log(val))

// `await` can only be used inside an async function
async function main() {
  const value = await modelPromise;
  console.log(value);
}

The fetch() function and then() method both return a Promise object. You assigned that Promise object to modelData and it will stay as a Promise object and will not be reassigned to the fulfilled value automatically.

To get the fulfilled value, you could either use the then() method or await keyword.

// name it `modelPromise` to be clear
const modelPromise = fetch("./modelData.json")
           .then(res => res.json())
           .then(val => val)

modelPromise.then(val => console.log(val))

// `await` can only be used inside an async function
async function main() {
  const value = await modelPromise;
  console.log(value);
}
南街女流氓 2025-01-24 03:29:48

你可以这样做

    var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => {
               console.log(val)      
            })

Promise(fulfilled) 的原因是因为 javascript 运行同步而不是异步,所以你需要像上面一样链接 .then 或在异步块中运行它。

const printmodeldata = async () => {
     const data = await modelData;
     console.log(data);
}

printmodeldata();

You can do it like this

    var modelData = fetch("./modelData.json")
           .then((res) => res.json())
           .then((val) => {
               console.log(val)      
            })

The reason for Promise(fulfilled) is because javascript runs sync instead of async so you would need to chain .then like above or run it in an async block.

const printmodeldata = async () => {
     const data = await modelData;
     console.log(data);
}

printmodeldata();
风吹雨成花 2025-01-24 03:29:48

如果您确实想要执行基于 setTimeout() 的方法,那么以下方法可能会起作用(这完全取决于承诺需要多长时间才能实现)。

var modelData;
fetch("https://jsonplaceholder.typicode.com/users/3")
       .then((res) => res.json())
       .then((val) => modelData=val);

setTimeout(()=>console.log(modelData),100);

但最终这并不比简单地将 console.log() 放入最终的.then() 中更容易。通过这种方法,您可以确保在履行承诺后立即得到结果。而且,作为奖励,收到的结果将可用于全局变量 modelData 中进一步的事件驱动交互。

var modelData;
fetch("https://jsonplaceholder.typicode.com/users/3")
       .then((res) => res.json())
       .then((val) =>{
  modelData=val;
  console.log(modelData);
});

If you really want to do a setTimeout() based approach then the following will probably work (it all depends on how long the promise will take to be fulfilled).

var modelData;
fetch("https://jsonplaceholder.typicode.com/users/3")
       .then((res) => res.json())
       .then((val) => modelData=val);

setTimeout(()=>console.log(modelData),100);

But in the end this is not any easier than simply placing your console.log() into the final .then(). With this approach you can be sure to get the result as soon as the promise is fulfilled. And, as a bonus, the received result will be available for further event-driven interactions in the global variable modelData.

var modelData;
fetch("https://jsonplaceholder.typicode.com/users/3")
       .then((res) => res.json())
       .then((val) =>{
  modelData=val;
  console.log(modelData);
});

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文