当我用巴别塔实践我到目前为止所学到的关于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()中设置的,但不能在它之外进行访问。
我哪里做错了?
发布于 2017-01-26 20:02:18
我不明白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 );
})这不是我最初想要的,我也没有知识来解释“为什么”,但是,至少这是一个明显的工作例子,我谦虚地希望它能帮助其他试图从非常长的答案和/或无用/无指导的评论中提取信息的人。
发布于 2017-01-26 20:39:56
有关如何使用Ajax等异步操作的结果的(冗长)入门,请参阅How do I return the response from an asynchronous call?。
简短的答案是:如果您正在同步一个值,那么就不能使用return异步获取的结果。您的getData函数在任何Ajax调用解析之前返回,因此getData的同步返回值不能依赖于任何异步获取的值。必须在处理任何新事件之前完全解决。处理异步Ajax结果是一个新事件,因此在getData函数执行成为历史之前,您的done处理程序不一定会运行。
解决问题的两种一般方法是:
使Ajax调用synchronous
getData外部异步访问
可以通过将回调传递到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的用法,并导致异步模式在你的代码中传播?是的,确实如此。
如果你想使用return a promises,你可以这样做
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 );
});
}这之所以有效,是因为promises允许链接then调用。这只是在get data函数内部和外部链接then:一个then回调在getData内排队,下一个在getData外排队。第一个回调的返回值用作第二个回调的参数。then的返回值是最初的promise,所以我简单地使用了表单return mypromise.then(...),它返回的对象就像我刚刚返回的return mypromise一样(但很明显,在这种情况下我没有设置回调)。
https://stackoverflow.com/questions/41850805
复制相似问题