在 then 函数之外访问 JavaScript Promise。

5

我正在尝试使用JavaScript在then函数之外访问Promise中的值。我是Promise的新手,不确定我是否做得正确。以下是我的代码:

//removed code

基本上我已将Promise返回的值存储在then函数内的单独变量中。我想在稍后的部分访问它们,但当我在稍后的部分打印它们时,它返回未定义。有什么解决办法吗?
我发现了示例并按照它们进行了操作,但没有起作用。我不确定我的代码哪里出错了。我之前开了一个帖子,被标记为重复并关闭了。我想我的问题不够清楚,因此我在这里重新表述问题。

1
在创建承诺后,您试图直接记录p1和p2。承诺是异步的,这意味着这些值直到承诺解决之后才会被设置,这就是为什么您得到undefined。此外,您正在对承诺解决的值进行promise.all操作,而不是对承诺本身进行操作。这样做是行不通的。如果您将Promise.all p1、p2的值替换为promiseStoreKey和promiseCurrencyKey,您可能会有更好的运气。 - jas7457
5
有两种 JavaScript 程序员:一种是理解异步编程的,另一种则不理解。理解异步代码的程序员... - Gerardo Furtado
@jas7457 谢谢,通过将p1和p2更改为您提到的密钥,它可以正常工作! - user7691120
3个回答

3
这是我最近发布的一个有效的 Promise 示例: Promise 骨架。 它是以 ES6 为基础的,因此将

替换成
return new Promise((y,n) => setTimeout( () =>  y('secondCall'), 800 ));

使用

return new Promise( function(resolve,reject) {
//... here you call your firebase and resolve(returnValue) once you get the result
});

在您的情况下

var currencyKey;
return new Promise( function(resolve,reject) {
       firebase.database().ref('currencies').orderByChild('currencySymbol').equalTo('$').once('value', function(snapshot) {
                var currencyData = snapshot.val();
                if (currencyData){
                  console.log('currency exists.');
                }else{
                    currencyKey = firebase.database().ref('currencies').push({
                    currencyName : "Singapore Dollar",
                    currencySymbol : "$"
                  }).getKey();

                  resolve(currencyKey);
                }
              });
        });
});

请注意,我在promise上方添加了var currencyKey;。这使得currencyKey可以在Promise代码块之外访问。


但是我在后面如何访问它?只需调用currencyKey吗? - user7691120
@EmmaHannah 我已修改了代码(如上所示),并将 var currencyKey 放在 Promise 上面。这样可以让其余的代码访问它。你遇到了一个作用域问题。这应该可以解决它。 - Jarek Kulikowski

2
为了在两个Promise对象都返回结果时执行逻辑,应该使用Promise.all()方法。
  Promise.all([promiseCurrencyKey, promiseStoreKey]).then(values => { 
    console.log(values); 
  });

JavaScript是一种单线程语言,这意味着当代码等待某些事件发生时会阻塞其他所有代码的执行。但我们实际上不能没有有时需要一段时间才能完成的任务,这就是Promise的作用所在。
Promise中的逻辑在后台运行,不会阻塞代码的执行。为了使用Promise解析出的值,可以将回调函数设置到then()方法中,该函数将在值解析时执行。
回调函数的执行不会使其他代码等待。
因此,代码的运行过程如下:
1.在后台运行某些逻辑,以解析值 2.当值被解析时,将其设置为p1 3.打印p1 - 步骤1中的逻辑尚未完成,这意味着then()函数中的逻辑也没有执行,值仍未设置到p1中 p2也是同样的情况。
现在,当你使用Promise.all()在两个简单的空变量上执行时,它不会应用于Promise对象,因此结果是一个包含两个空变量的数组...
在第二个例子中,问题在于你在第一个Promise函数内部定义了promiseBranchKey,因此它仅存在于该函数范围内,并且在调用Promise.all()时不存在。
let promiseMerchantKey = new Promise((resolve, reject) => {
    firebase.database().ref('merchants').orderByChild('merchantName').equalTo('NTUC').once('value', function(snapshot) {
        let merchantData = snapshot.val();
        if (merchantData){
            console.log('merchant exists');
            resolve(merchantData.key);
        }else{
            // get merchant unique push ID
            let merchantKey = firebase.database().ref('merchants').push({
                address : "NTUC"
            }).getKey();
            resolve(merchantKey);
        }
    });
});

let promiseBranchKey = new Promise((resolve, reject) => {
    firebase.database().ref('merchants').orderByChild('branchAddress').equalTo('Blk 167').once('value', function(snapshot) {
        let branchData = snapshot.val();
        if (branchData){
            console.log('branch exists');
            resolve(branchData.key);
        }else{
            // get branch unique push ID
            promiseMerchantKey.then((merchantKey) => {
                let branchKey = firebase.database().ref('merchants').child(merchantKey).push({
                    branchName : 'Marsiling',
                    branchAddress : 'Blk 167'
                }).getKey();
                resolve(branchKey);
            });
        }
    });
});

promiseBranchKey.then((branchKey) => { 
    console.log('branchkey' + branchKey); 
    console.log('currencykey' + promiseMerchantKey);
});

考虑到 Promise 2 依赖于 Promise 1 返回的值,因此您应该在 Promise 2 中使用 then() 方法,并且只有当第一个 Promise 已经返回值时才会导致 Promise 2 的解决。

由于只有在 Promise 1 已经解决时才能解决 Promise 2,所以不需要使用 promise.all(),我们可以在 Promise 2 上使用 then 来指示它们都已被处理。


你能帮我看一下编辑部分吗?我目前遇到的错误是“找不到变量:promiseBranchKey”。 - user7691120
你在第一个Promise函数内定义了promiseBranchKey,所以它只存在于此函数的范围内,在调用Promise.all()的位置外部不存在。 - Ori Shalom
有什么解决这个问题的想法吗? - user7691120

1

其中一个方法是利用async/await

async function getData() {
  const p1 = await new Promise(resolve => 
               setTimeout(resolve, Math.floor(Math.random() * 1200), "p1"));
  console.log(p1);
  const p2 = await new Promise(resolve => 
               setTimeout(resolve, Math.floor(Math.random() * 1500), "p2"));
  console.log(p2);
  // do stuff
  // access `p1`, `p2` "later"
  const p3 = await Promise.all([p1, p2])
             .then(results => 
                new Promise(resolve => 
                  setTimeout(resolve, 1800, [...results, "p3"]))
             );
             
  console.log(p3);
  
  return [...p3, "p4"]
}

getData()
.then(res => console.log(res))

或者,只需链接 .then().catch() 调用而不是嵌套 Promise 调用;尽管嵌套 .then()Promise 调用也不应该有问题。

重要的是确定在执行过程中给定点的预期结果是什么。


嘿,你能检查一下我编辑的部分吗?我已经让它工作了。但是假设我的分支需要来自商家的承诺,我将其嵌套在内部,但是底部的Promise.all告诉我一个错误消息,说找不到promiseBranchKey。有任何想法如何纠正这个问题吗? - user7691120
你收到了一个错误吗?在哪里?JavaScript问题中没有出现.catch().then()的第二个参数。问题是您没有从.then()返回值,请从链接到promiseMerchantKey.then()链接返回return promiseBranchKeypromiseMerchantKey.then((merchantKey) => { let promiseBranchKey = new Promise((resolve, reject) => {}); return promiseMerchantKey})。请参阅为什么Promise链接中的值未定义? - guest271314
是的,错误告诉我找不到变量promiseBranchKey,我猜这是因为它嵌套在then函数内部。抱歉,但我很困惑,如果是这种情况,我应该改变什么?对于承诺,它们不再是未定义的,因为我使用了.all测试了其他承诺,它实际上打印出了值。 - user7691120
是的,我几天前尝试使用了await和async。然而,出现了一些错误,指出await是一个保留关键字。因此,我在EDIT部分找到了一种替代方法。目前它可以正常工作,因为我成功地检索到了值,但是有一个问题,例如我有promise1和promise2。Promise2需要从promise1获取值,因此我将promise2嵌套在promise1的then函数中。当我试图在最后打印输出时,出现了一个错误消息,说“找不到变量:promise2”,因为我在promise1的then函数中声明了promise2。 - user7691120
1
我知道了,非常感谢你的所有帮助!!! - user7691120
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接