【问题标题】:Variable set by await is undefined after await expression evaluated在等待表达式评估后,由等待设置的变量未定义
【发布时间】:2018-08-03 19:19:11
【问题描述】:

我有一些使用 async/await 的代码给我带来了一个非常奇怪的问题:我用 await 语句设置的变量在表达式之后抛出了一个未定义的引用 rrror!代码如下:

export const fetchPrices = async ({ commit }, ticker) => {
  const key= "*********";
  const url =
    `http://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${ticker}&interval=1min&apikey=${key}`

  commit(FETCH_PRICES_REQUEST, { ticker })

  try {
    let response = await fetch(url);
    let priceData = await response.json();
  }
  catch (e) {
    console.error(e);
  }

  commit(FETCH_PRICES_SUCCESS, priceData)
};

运行时,函数的最后一行会抛出几个错误:

ReferenceError: 响应未定义

Uncaught (in promise) ReferenceError: priceData is not defined

这对我来说没有多大意义,因为我的理解是 await 的整个用法是对变量的赋值应该由下一行代码完成。

我实际上已经解决了这个问题,这与我声明变量的位置有关。当我通过将以下行放在函数顶部将声明移到 try/catch 块之外时,它起作用了:

let response, priceData;

出于好奇,我在 Babel 中查看了转换后的代码。文件顶部的声明如下所示:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

var fetchPrices = exports.fetchPrices = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref2, ticker) {
    var commit = _ref2.commit;
    var response, priceData, key, url;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            response = void 0, priceData = void 0;
            key = "EH6GPZQ5X8EUM3MC";
            url = "http://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=" + ticker + "&interval=1min&apikey=" + key;


            commit(FETCH_PRICES_REQUEST, { ticker: ticker });

            _context.prev = 4;
            _context.next = 7;
            return fetch(url);

          case 7:
            response = _context.sent;
            _context.next = 10;
            return response.json();

          case 10:
            priceData = _context.sent;
            _context.next = 16;
            break;

          case 13:
            _context.prev = 13;
            _context.t0 = _context["catch"](4);

            console.error(_context.t0);

          case 16:

            commit(FETCH_PRICES_SUCCESS, priceData);

          case 17:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, undefined, [[4, 13]]);
  }));

  return function fetchPrices(_x, _x2) {
    return _ref.apply(this, arguments);
  };
}();

关键区别在于第一个案例顶部的行 (case 0):

response = void 0, priceData = void 0;

似乎发生的情况是,如果您不在函数顶部声明变量,那么案例 7 和案例 10 在尝试分配给这些变量时会失败。

我的问题是这是否是 async/await 编译代码的问题,或者我尝试在 try/catch 块中声明变量是否根本错误。

【问题讨论】:

  • let 是块作用域。当您在 try{} 中声明这些变量时,它们的作用域是由大括号创建的块。
  • 用 let/const 定义的变量是阻塞范围
  • @Akrion response 是,但在 try/catch 之外,操作尝试使用 priceData,其范围仍为 try。这个场景是一个完美的例子,将这些请求添加到数组并使用promise.all 解析和运行`commit(FETCH_PRICES_SUCCESS, priceData)` 函数,imo。
  • @MarkMeyer,我更改了几次变量名,忘记更新我在问题中的评论。我马上更新。
  • @fraxture,这个问题真的是一个范围问题,但是promise.all 会在你可能有多个连续等待时减轻痛苦。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

标签: javascript async-await


【解决方案1】:

这里的解决方案——正如@Mark Meyer 和@sesamechicken 所指出的——是一个范围界定错误。 Let 是块范围的,因此 priceData 在 try {} 块之外未定义。解决方案是在 try 块之外定义这些变量。使用var 也可能有效。

【讨论】:

    猜你喜欢
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 2015-05-22
    • 2018-11-17
    • 1970-01-01
    • 2019-06-18
    • 2020-05-12
    • 1970-01-01
    相关资源
    最近更新 更多