【问题标题】:Assign value from successful promise resolve to external variable将成功的承诺解析中的值分配给外部变量
【发布时间】:2015-09-24 16:19:48
【问题描述】:

我有一个非常愚蠢的问题。考虑以下几点:

vm.feed = getFeed().then(function(data) {return data;});

getFeed() 返回一个成功解决的 $q 延迟承诺(我在 Angular 上)。

我的目标是设置 vm.feed 等于成功回调返回的数据值。就像现在一样,代码只是将 vm.feed 分配为等于 getFeed() 返回的 $promise 对象。

我知道我可以简单地在解析函数中执行:vm.feed = data,但我想了解为什么这段代码不能按原样工作。

PD:promise 正确解析,即使在它被解析之后 vm.feed 仍然等于 Promise,而不是数据。我在 +10 秒后复制了 vm.feed 的 console.log:

Promise {$$state: Object} $$state: Objectstatus:1 value: Object

Promise 对象内的 value 属性包含我要分配给 vm.feed 的 Promise 的实际解决方案(例如data)。

谢谢!

【问题讨论】:

  • 使用 vm.feed = getFeed().then(function(data) {return data.data ;});
  • Promise 被返回是有原因的:结果不是立即可用,而是经过一段时间的延迟。将其分配给全局变量为各种同步问题打开了大门(数据是否已经存在?)。最好的解决方案是在 promise 的回调中触发所有涉及返回数据的功能。
  • 如果getFeed 使用$http 考虑使用$resource,它会返回一个空对象(不是承诺),当资源响应时会被填充
  • 嗨,promise 可以正确解析,即使它已经解决,vm.feed 仍然等于Promise。在问题正文中经过 +10 秒后,我复制了 vm.feed 的控制台日志。
  • 您好 fantarama,感谢您的提示,我仍然想知道为什么我提供的代码不起作用。

标签: javascript angularjs


【解决方案1】:

无论then() 返回什么,你都会得到。但既然您正在阅读本文,以下内容可能会对您有所帮助:

您的语句只是要求解释器将从then() 返回的值分配给vm.feed 变量。 then() 给你一个 Promise(你可以在这里看到:https://github.com/angular/angular.js/blob/ce77c25b067b7b74d90de23bfb4aac6a27abb9d1/src/ng/q.js#L288)。您可以通过看到 Promise(一个简单的对象)被 拉出 出函数并分配给 vm.feed 来想象这一点。一旦解释器执行该行,就会发生这种情况。

由于当您调用 then() 时成功的回调不会运行,但只有在您的承诺得到解决时(稍后,异步),then() 不可能为调用者返回其值。这是 Javascript 的默认工作方式。这就是引入 Promise 的确切原因,因此您可以要求解释器以回调的形式推送值给您。

尽管在 JavaScript (ES2016) 的未来版本中,我们将引入几个关键字来实现您现在所期望的工作。好消息是,您现在可以通过从 ES2016 转换到当前广泛支持的版本 (ES5) 开始编写这样的代码。

有关该主题的精彩介绍可在:https://www.youtube.com/watch?v=lil4YCCXRYc

要立即使用它,您可以通过 Babel 转译您的代码:https://babeljs.io/docs/usage/experimental/(通过运行 --stage 1)。

您还可以在此处查看一些示例:https://github.com/lukehoban/ecmascript-asyncawait

【讨论】:

  • 一旦promise在问题正文中得到解决,我就复制了vm.feed值;它仍然等于 Promise 对象而不是 data,一旦 promise 解决,它不应该改变吗?
  • 在 Javascript 中,变量的值仅由用户代码设置。一旦解释器运行了那行代码,它就不会更改变量,直到您给出的其他指令将其值设置为其他值。
  • 仅供参考,您尝试实现的目标将在 ES2016 中使用 await 关键字提供。如果您有兴趣:youtube.com/watch?v=lil4YCCXRYc :)
  • 使用 .ajax 从 php 查询中获取数据会更好吗?我在任何地方都看不到任何将 php encode_json 中的数据从 promise 分配到 javascript 中的 json 数组的示例代码。到目前为止,我只能在 .ajax 中执行此操作。
【解决方案2】:

这可以通过箭头函数更新到 ES6,如下所示:

getFeed().then(data => (vm.feed = data));

如果你想使用async function,你也可以这样做:

async function myFunction(){
    vm.feed = await getFeed();
    // do whatever you need with vm.feed below
 }

编辑:添加括号以确保正确(由 Max Waterman 评论)

【讨论】:

  • 如果我想返回和导出 vm.feed 的值并将其作为参数进一步传递给不同的 js 文件中的一个完全不同的函数,该文件接受 String 类型的参数(假设:vm.feed包含字符串类型的数据)。这里返回 vm.feed 将再次成为一个 Promise,所以我不能将它传递给该函数。我们有没有办法从 Promise 中检索数据并将其分配给一个变量以进一步用作非 Promise 对象?
  • 阿杰,在“等待”之后,不再是承诺了。
  • 感谢 Soldeplata 的回复!你是对的,但是如果我从异步函数内部返回一个值,它又是一个 Promise。所以我不能返回非承诺数据以在不同的函数中进一步使用。
  • 带有 es6 箭头函数的示例的旁注:eslint.org/docs/rules/no-return-assign
【解决方案3】:

then() 方法返回一个 Promise。它有两个参数,都是 Promise 成功和失败情况的回调函数。 Promise 对象本身不会直接为您提供解析的数据,该对象的接口仅通过提供的回调提供数据。所以,你必须这样做:

getFeed().then(function(data) { vm.feed = data;});

then() 函数返回具有前一个then() 回调的解析值的承诺,允许您将值传递给后续回调:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved
// and its value will be the result of promiseA incremented by 1

【讨论】:

  • 我同意,但是如果回调返回解析的数据本身,它不应该在 Promise 对象之外可用吗?
  • 将成功回调的返回值传入后续成功回调的成功回调中,让你沿着调用链(责任链)传递变异值
  • 但是在这个例子中,如果你声明了 vm.feed,让我们在开始时说,然后你 console.logged vm.feed 它将作为 undefined 运行。
【解决方案4】:

您可以为您的函数提供对象及其属性。接下来,在函数内部做你需要做的事情。最后,将 Promise 中返回的值分配到对象中的正确位置。这是一个例子:

let myFunction = function (vm, feed) {
    getFeed().then( data => {
        vm[feed] = data
    })
} 

myFunction(vm, "feed")

如果需要,您还可以编写自调用函数。

【讨论】:

  • 这个答案与@SoldeplataSaketos 发布的答案有何实质性不同?
【解决方案5】:

这是你可以做的一个“技巧”,因为你没有异步功能,所以不能使用等待键

在 setTimeout 内用 vm.feed 做你想做的事

vm.feed = getFeed().then(function(data) {return data;});

 setTimeout(() => {
    // do you stuf here
    // after the time you promise will be revolved or rejected
    // if you need some of the values in here immediately out of settimeout
    // might occur an error if promise wore not yet resolved or rejected
    console.log("vm.feed",vm.feed);
 }, 100);

【讨论】:

    猜你喜欢
    • 2017-04-26
    • 2020-05-10
    • 2020-04-30
    • 1970-01-01
    • 2015-12-13
    • 2019-09-18
    • 2019-11-11
    • 2018-08-30
    • 2020-01-10
    相关资源
    最近更新 更多