链式承诺和原型“this”
Chained promises and prototype `this`
我很难获得在原型中使用正确 this
范围的承诺。
这是我的代码:
'use strict';
angular.module('testApp').factory('UrlSearchApi',
function($resource, URL_SEARCH_API, PAGE_SIZE, $q){
var resource = $resource(URL_SEARCH_API);
resource.Scroll = function () {
return this.reset();
};
resource.Scroll.prototype.reset = function () {
this.visibleItems = [];
this.allItems = [];
this.busy = null;
return this;
};
resource.Scroll.prototype.fetch = function(query){
var params = {};
if(query) { params.q = query; }
return resource.query(params).$promise;
};
resource.Scroll.prototype.loadAllItems = function (results) {
var d = $q.defer();
angular.forEach(results, function (result, i) {
this.allItems.push(result);
if(i === results.length - 1 ) { d.resolve(); }
}, this);
return d.promise;
};
resource.Scroll.prototype.loadVisibleItems = function () {
var length = this.visibleItems.length,
offset = parseInt(length / PAGE_SIZE),
start = PAGE_SIZE * offset,
end = start + PAGE_SIZE,
subset = this.allItems.slice(start, end),
d = $q.defer();
angular.forEach(subset, function (item, i) {
this.visibleItems.push(item);
if(i === subset.length - 1 ) { d.resolve(); }
}, this);
return d.promise;
};
resource.Scroll.prototype.nextPage = function (query) {
if(this.busy) { return; }
console.log('nextPage ', query);
var tasks = [],
that = this;
if(!this.allItems.length) {
this.reset();
this.busy = true;
return this.fetch(query)
.then(this.loadAllItems)
.then(this.loadVisibleItems)
.finally(function () {
this.busy = false;
});
} else {
this.busy = true;
return this.loadVisibleItems().finally(function () {
this.busy = false;
});
}
};
return resource;
});
每当我 运行 我得到的测试
describe('#nextPage', function () {
var scroll;
describe('when there is NO search term (show all)', function () {
beforeEach(function (done) {
scroll = new UrlSearchApi.Scroll();
$httpBackend.expectGET('/policy/search')
.respond(200, arrayGenerator(123));
scroll.nextPage().then(done);
$httpBackend.flush();
$rootScope.$apply();
});
it('should load all the items in all items variable', function () {
expect(scroll.allItems.length).toBe(123);
});
});
});
我收到以下错误:
TypeError: 'undefined' is not an object (evaluating 'this.allItems')
我现在 $q
在严格模式下将 then
内的 this
设置为 undefined
。我尝试在多个地方使用 bind(this)
但运气不好...有什么想法吗?
我已经回答过这样的问题。
如果您还有疑问,请在评论中告诉我。
Upd. 尝试像这样更新您的 resource.Scroll.prototype.nextPage 方法:
if(!this.allItems.length) {
this.reset();
this.busy = true;
return this.fetch(query)
.then(this.loadAllItems.bind(this)) //bind here
.then(this.loadVisibleItems.bind(this)) // here
.finally(function () {
this.busy = false;
}.bind(this)); //and here
但请记住 - 当您将函数作为回调 传递给 then
或 forEach
e.t.c 它会丢失 this
上下文 。因此,当您传递使用 this
语法作为回调的函数时,请准确使用 bind
。
我很难获得在原型中使用正确 this
范围的承诺。
这是我的代码:
'use strict';
angular.module('testApp').factory('UrlSearchApi',
function($resource, URL_SEARCH_API, PAGE_SIZE, $q){
var resource = $resource(URL_SEARCH_API);
resource.Scroll = function () {
return this.reset();
};
resource.Scroll.prototype.reset = function () {
this.visibleItems = [];
this.allItems = [];
this.busy = null;
return this;
};
resource.Scroll.prototype.fetch = function(query){
var params = {};
if(query) { params.q = query; }
return resource.query(params).$promise;
};
resource.Scroll.prototype.loadAllItems = function (results) {
var d = $q.defer();
angular.forEach(results, function (result, i) {
this.allItems.push(result);
if(i === results.length - 1 ) { d.resolve(); }
}, this);
return d.promise;
};
resource.Scroll.prototype.loadVisibleItems = function () {
var length = this.visibleItems.length,
offset = parseInt(length / PAGE_SIZE),
start = PAGE_SIZE * offset,
end = start + PAGE_SIZE,
subset = this.allItems.slice(start, end),
d = $q.defer();
angular.forEach(subset, function (item, i) {
this.visibleItems.push(item);
if(i === subset.length - 1 ) { d.resolve(); }
}, this);
return d.promise;
};
resource.Scroll.prototype.nextPage = function (query) {
if(this.busy) { return; }
console.log('nextPage ', query);
var tasks = [],
that = this;
if(!this.allItems.length) {
this.reset();
this.busy = true;
return this.fetch(query)
.then(this.loadAllItems)
.then(this.loadVisibleItems)
.finally(function () {
this.busy = false;
});
} else {
this.busy = true;
return this.loadVisibleItems().finally(function () {
this.busy = false;
});
}
};
return resource;
});
每当我 运行 我得到的测试
describe('#nextPage', function () {
var scroll;
describe('when there is NO search term (show all)', function () {
beforeEach(function (done) {
scroll = new UrlSearchApi.Scroll();
$httpBackend.expectGET('/policy/search')
.respond(200, arrayGenerator(123));
scroll.nextPage().then(done);
$httpBackend.flush();
$rootScope.$apply();
});
it('should load all the items in all items variable', function () {
expect(scroll.allItems.length).toBe(123);
});
});
});
我收到以下错误:
TypeError: 'undefined' is not an object (evaluating 'this.allItems')
我现在 $q
在严格模式下将 then
内的 this
设置为 undefined
。我尝试在多个地方使用 bind(this)
但运气不好...有什么想法吗?
我已经回答过这样的问题
Upd. 尝试像这样更新您的 resource.Scroll.prototype.nextPage 方法:
if(!this.allItems.length) {
this.reset();
this.busy = true;
return this.fetch(query)
.then(this.loadAllItems.bind(this)) //bind here
.then(this.loadVisibleItems.bind(this)) // here
.finally(function () {
this.busy = false;
}.bind(this)); //and here
但请记住 - 当您将函数作为回调 传递给 then
或 forEach
e.t.c 它会丢失 this
上下文 。因此,当您传递使用 this
语法作为回调的函数时,请准确使用 bind
。