【问题标题】:Returning value from callback within Meteor.method从 Meteor.method 中的回调返回值
【发布时间】:2013-12-04 00:41:15
【问题描述】:

我在 Meteor 中遇到了一些我不理解的问题。我有这个方法,它接受一个查询,将它发送到亚马逊,然后在该函数的回调中我尝试返回结果。

Meteor.methods({
    'search': function(query) {
        var bookInfo;
        if (Meteor.isServer) {
            amazon.execute('ItemSearch', {
                'SearchIndex': 'Books',
                'Keywords': query,
                'ResponseGroup': 'ItemAttributes'
            }, function(results) {
                bookInfo = results;
                console.log(bookInfo);
                return bookInfo;
            });
        }
    }
});

但是当我在浏览器(chrome)的控制台中输入以下内容时:

Meteor.call('search', 'harry potter', function(error, response) {
    console.log('response:', response);
});

我明白了:

undefined
response: undefined          VM13464:3

我想我明白第一个 undefined 来自客户端上没有返回任何内容的方法,但回调似乎根本不起作用。

amazon.execute(...) 肯定会返回一些东西,因为返回上方的 console.log 确实记录了我正在寻找的信息。

任何想法出了什么问题以及如何解决它?

【问题讨论】:

    标签: javascript asynchronous callback meteor undefined


    【解决方案1】:

    你需要利用未来来实现你的目标。

    从 Meteor 0.6 开始如何使用 future?

    Meteor.startup(function () {
     Future = Npm.require('fibers/future');
    
     // use Future here
    }
    

    用 Future 重写你的方法:

    Meteor.methods({
     'search': function(query) {
    
        var future = new Future();
    
        amazon.execute('ItemSearch', {
                'SearchIndex': 'Books',
                'Keywords': query,
                'ResponseGroup': 'ItemAttributes'
        }, function(results) {
           console.log(results);
    
           future["return"](results)
    
        });
    
        return future.wait();
     }
    });
    

    现在应该可以了。

    Meteor.call('search', 'harry potter', function(error, response) {
       if(error){
        console.log('ERROR :', error);
       }else{
        console.log('response:', response);
       }
    
    });
    

    如果您想了解更多关于 Future 库的信息,我建议您观看screencast


    2017 年 12 月 26 日更新

    我只是想更新这个答案,因为您可以使用 Promise 实现相同的目标,因此摆脱“纤维”依赖 :)

    一个例子胜过千言万语

    import scrap from 'scrap';
    
    Meteor.methods({
        'hof.add'(el) {
            check(el, {
                _link: String
            });
    
            const promise = getHofInfo(el._link)
                .then((inserter) => {
                    inserter.owner = Meteor.userId();
                    Hof.insert(inserter);
                    return true;
                })
                .catch((e) => {
                    throw new Meteor.Error('500', e.message);
                });
            return promise.await();
        }
    });
    
    
    function getHofInfo(_link) {
        return new Promise((resolve, reject) => {
            scrap(_link, function (err, $) {
                if (err) {
                    reject(err);
                } else {
                    const attakers = $('#report-attackers').find('li').text();
                    const defender = $('#report-defenders').find('li').text();
                    const _name = attakers + ' vs ' + defender;
                    const _date = new Date();
                    resolve({ _name, _date, _link });
                }
            });
        });
    }
    

    【讨论】:

    • 我也面临这个问题。但我不想使用 npm 模块。有没有类似光纤未来的流星包
    • @MariyaJames 检查新的编辑,你可以在没有模块的情况下完成
    【解决方案2】:

    对于看到这个问题并想知道为什么像 Future 或 Fiber 这样的库的任何新接触 Meteor 的人来说,这是因为对 amazon.execute 的调用是异步的。 p>

    在 Javascript 中,许多需要较长时间的操作不会一行接一行地运行;例如写入数据库、使用 window.setTimeout 或发出 HTTP 请求。过去,使用此类方法,您需要将想要在事后运行的代码包装在 回调 中。

    Future 和 Fibers 提供语法糖和附加功能,但它们的核心功能是相同的。

    Meteor 使用特殊的幕后技巧使某些内置操作(如访问 MongoDB)显示同步,同时仍利用异步代码提高的性能。出于这个原因,您通常只需要在使用外部包(如本例中的亚马逊包)时担心异步。


    Here 是同时使用 Future 和 Fibers 的完整示例:

    the Discover Meteor blogthe Meteor Chef 上有一些很棒的文章解释了 Meteor 中 Sync/Async 的性质

    【讨论】:

      【解决方案3】:

      Meteor 方法是异步的,你可以通过多种方式获取结果。

      使用 npm 模块纤程(另一个答案解释得很清楚)。

      还有其他一些不使用 npm 模块的方法:

      通过会话变量:

          Meteor.call('myMethod',args, function(error, result) { 
        if (error) { Session.set('result', error) } // Note that the error is returned synchronously 
        else { 
          Session.set('result', result) // Using : Session.get('result') will return you the result of the meteor call !
        }
      });
      

      或者通过模板变量:

          Template.hello.onCreated(function helloOnCreated() {
        // counter starts at 0
        this.message = new ReactiveVar(0);
      });
      
      Template.hello.helpers({
        message() {
          return Template.instance().message.get();
        },
      });
      
      Template.hello.events({
        'click button'(event, instance) {
          Meteor.call('myMethod', args, function (error, result) {
            if (error) { Template.instance().message.set(error); }
            else {
              Template.instance().message.set(result);
            }
          })
        },
      });
      

      希望对您有所帮助!

      【讨论】:

        【解决方案4】:

        one better solution

        使用光纤包

        var Fiber = Npm.require('fibers');
        ...
        Meteor.methods({
            callAsync: function (args) {
                var fiber = Fiber.current;
        
                async(function (args) {
                    ...
                    fiber.run(res);
                });
        
                return Fiber.yield();
            }
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-08-18
          • 2012-03-27
          • 2020-04-22
          • 1970-01-01
          • 1970-01-01
          • 2014-03-01
          • 1970-01-01
          • 2021-06-01
          相关资源
          最近更新 更多