WeakMaps和AJAX调用

时间:2017-01-25 11:45:30

标签: javascript jquery ajax ecmascript-6 babeljs

在实践我迄今为止所学到的有关Babel的ES2015,特别是关于WeakMaps时,我遇到了一个问题,我不知道为什么它不起作用。

我定义了一个WeakMap来容纳来自AJAX调用的数据,只有当所述WeakMap的值为undefined时才会触发。

这就是我的目标:

class User {

    constructor( id ) {

        id = Number( id );

        if( id <= 0 || isNaN( id ) ) {
            throw new TypeError( 'Invalid User ID' );
        }

        _id.set( this, id );
    }

    getID() {
        return _id.get( this );
    }

    getData() {

        let _this = this;

        if( _data.get( _this ) === undefined ) {

            _this.loadData().done( function( data ) {

                // JSON is indeed successfully loaded

                console.log( data );

                _data.set( _this, data );

                // WeakMap is indeed set correctly

                console.log( _data.get( _this ) );
            });
        }

        // But here it's undefined again!

        console.log( _data.get( _this ) );

        return _data.get( _this );
    }

    loadData() {

        return $.get({
            url: '/users/' + _id.get( this, data ),
        });
    }
}

let _id   = new WeakMap;
let _data = new WeakMap;

// ---------------

var user = new User( 1 );

console.log( user.getID(), user.getData() ); // 1 undefined

据我所知,我正在正确设置WeakMap数据,因为正在设置用户ID并且可以检索,但是来自AJAX的用户数据虽然确实是在jQuery.done()内设置的不能在它之外访问。

我做错了什么?

2 个答案:

答案 0 :(得分:0)

我不明白JavaScript是不是说这是正确的解决方案但是我已经搜索了很多,在Stack Overflow中阅读了无数的问题,这些答案很难以简单的方式处理,对任何人来说都是如此感兴趣的是:

class User {

    constructor( id ) {

        id = Number( id );

        if( id <= 0 || isNaN( id ) ) {
            throw new TypeError( 'Invalid User ID' );
        }

        _id.set( this, id );
    }

    getID() {
        return _id.get( this );
    }

    getData() {

        if( _data.get( this ) === undefined ) {
            _data.set( this, this.loadData() );
        }

        return _data.get( this );
    }

    loadData() {
        return $.getJSON( CARD_LIST + '/player/' + _id.get( this ) );
    }
}

let _data = new WeakMap;

// ---------------

var user = new User( 1 );

user.getData().done( function( data ) {

    console.log( data );
})

这不是我最初的想法,我没有解释“为什么”的知识,但至少这是一个明显的工作示例,我谦卑希望这将有助于其他人试图从极端提取信息长答案和/或无益/无指导的评论。

答案 1 :(得分:0)

有关如何使用Ajax等异步操作结果的(冗长)入门,请参阅How do I return the response from an asynchronous call?

简短的回答是:如果您同步return某个值,则不能使用异步获取的结果。您的getData函数在任何Ajax调用解析之前返回,因此同步返回值getData不能依赖于任何异步获取的值。这甚至不等于等待&#34;足够长:JavaScript事件处理的基本原则是当前函数堆栈(即当前函数和直接调用该函数的函数等)必须在处理任何新事件之前完全解析。处理异步Ajax结果是一个新事件,因此在done函数执行是古代历史之后,getData处理程序必然不会运行。

解决问题的两种常用方法是:

  1. 使Ajax调用同步

  2. getData

  3. 之外异步访问Ajax获取的值

    您可以通过将回调传递到getData来执行#2,例如

    getData(funnction(data) { console.log("If this is running, we finally got the data", data); }
    
    function getData(callback) {
        _this.loadData.done(function(data) {
            _data.set(this, data);
            // etc. etc.
            callback(_data.get( _this ));
        });
    }
    

    所以,现在getData本身是异步的,这是否会强制你重写你已经拥有的`getData的任何使用,并导致在你的代码中传播异步模式?是的,确实如此。

    如果你想使用返回承诺,你可以做

    getData().then(function(data) {
        console.log("Got the data", data);
    });
    
    function getData() {
        return _this.loadData().then(function(data) {
            _data.set(this, data);
            // etc. etc.
            return _data.get( _this );
        });
    }
    

    这是有效的,因为承诺允许链接then来电。这只是在get数据函数内部和外部链接then:一个then回调在getData内排队,而下一个回调在getData之外排队。第一个回调的返回值用作第二个回调的参数。 then的返回值是原始承诺,因此我只使用了return mypromise.then(...)形式,它返回了相同的对象,就像我刚刚完成return mypromise一样(但显然我在这种情况下还没有设置回调。)