我有一个服务,它公开了一个函数,该函数接收一个解析的CSV(使用Papapass),并promise反映解析状态:
如果文件缺少强制字段,promise将被拒绝
否则,它将每行解析为一个项,并自动填充缺少字段(自动填充过程是异步的)。
当所有项都被填充时,函数用项数组解析promise
angular.module('csvParser', [])
.factory('csvParser', ['$http',
function($http) {
var service = {
onCsvParse: function(results, creatingBulkItems) {
var errors = this.getCsvErrors(results);
if (errors.length > 0) {
//reject
creatingBulkItems.reject(errors);
} else {
var items = this.parseCsv(results);
var autoPopulateItems = [],
populatedItems = [];
for (var i = 0; i < populatedItems.length; i++) {
var item = items[i];
if (item.name === "" /*or some any field is missing */ ) {
// auto populate item
autoPopulateItems.push(this.autoPopulateItem(item));
} else {
var populatedItem = $q.when(item);
populatedItems.push(populatedItem);
}
}
populatedItems =autoPopulateItems.concat(populatedItems);
var populatingAllItems = $q.all(populatedItems);
populatingAllItems.then(function(items) {
creatingBulkItems.resolve(items);
}, function(err) {
creatingBulkItems.resolve(err);
});
}
},
autoPopulateItem: function(newItem) {
var populatingItem = $q.defer();
var item = angular.copy(newItem);
$http.post('api/getItemData', { /*.....*/ })
.success(function(response) {
//----Populate item fields
item.name = response.name;
//....
//resolve the promise
populatingItem.resolve(item)
}).error(err) {
// resolving on error for $q.all indication
populatingItem.resolve(item)
};
return populatingItem.promise;
}
}
return service;
}
])
我对该方法的测试如下(简化):
describe('bulk items upload test', function() {
//upload csv & test scenarios...
var $rootScope, $q, csvResults = {};
var $httpBackend, requestHandler;
beforeEach(module('csvParser'));
beforeEach(inject(function(_$rootScope_, _$q_) {
$rootScope = _$rootScope_;
$q = _$q_;
}));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
requestHandler = $httpBackend.when('POST', 'api/getItemData')
.respond({
name: "name",
description: "description",
imageUrl: "www.google.com"
});
// afterEach(function(){ $rootScope.$apply();});
}));
it('Should parse csv string', function(done) {
var csvString = "Name,Description of the page";//...
Papa.parse(csvString, {
complete: function(results) {
csvResults = results;
done();
}
});
});
it('Should fail', function(done) {
var creatingBulkItems = $q.defer();
console.log("here..");
csvParser.onCsvParse(csvResults, creatingBulkItems);
creatingBulkItems.promise.then(function() {
console.log("1here..");
//promise is never resolved
expect(1).toEqual(1);
done();
}, function() {
//promise is never rejeceted
console.log("2here..");
expect(1).toEqual(1);
done();
});
$rootScope.$apply();
});
});
这样我得到了一个错误:error:Timeout-Async回调没有在jasmine指定的超时内调用。默认超时时间间隔。
虽然我调用了$rootScope,但promise没有得到解决$apply()并且我也没有调用真正的异步调用(只调用mock,除了$q.all)。我怎样才能让它工作?
读完这篇文章后:https://gist.github.com/domenic/3889970 我发现了我的问题
关键的一点是使用promise扁平化promise链。然后返回值。
这个[promise.then]函数应该返回一个新的promise,当给定的满足处理程序或错误处理程序回调结束时,这个promise就会实现。这允许将promise操作链接在一起。从回调处理程序返回的值是返回的promise的实现值。如果回调抛出一个错误,返回的promise将被移动到失败状态。
不是在内部promise成功/失败回调中解决外部promise,而是在内部promise.then回调中解决外部promise
所以我的解决方案是这样的:
onCsvParse: function(results) {
var errors = this.getCsvErrors(results);
if (errors.length > 0) {
var deferred = $q.defer();
//reject
return deferred.reject(errors);
} else {
var items = this.parseCsv(results);
var autoPopulateItems = [],
populatedItems = [];
for (var i = 0; i < populatedItems.length; i++) {
var item = items[i];
if (item.name === "" /*or some any field is missing */ ) {
// auto populate item
autoPopulateItems.push(this.autoPopulateItem(item));
} else {
var populatedItem = $q.when(item);
populatedItems.push(populatedItem);
}
}
populatedItems = autoPopulateItems.concat(populatedItems);
var populatingAllItems = $q.all(populatedItems);
return populatingAllItems.then(function(items) {
return items;
}, function(err) {
return err;
});
}
},
测试代码:
it('Should not fail :)', function(done) {
csvParser.onCsvParse(csvResults).then(function(items) {
//promise is resolved
expect(items).not.toBeNull();
done();
}, function() {
//promise is rejeceted
//expect(1).toEqual(1);
done();
});
$rootScope.$apply();});
无效的语法。您需要传递一个函数到错误
回调。
}).error(function(err) {
// resolving on error for $q.all indication
populatingItem.resolve(item)
});
return populatingItem.promise;
另外你jasime测试需要一些更多的初始化:http://plnkr.co/edit/wjykvpwtRA0kBBh3LcX3?p=preview
本文向大家介绍列举一个你觉得互联网中存在价格歧视的产品,并从开发者与用户的角度来分析这种歧视是否合理。相关面试题,主要包含被问及列举一个你觉得互联网中存在价格歧视的产品,并从开发者与用户的角度来分析这种歧视是否合理。时的应答技巧和注意事项,需要的朋友参考一下 举例:携程会就同一产品对不同画像的用户提供不同面额的优惠券,从而导致不同用户购买同一产品所支付的实际价格有差异。 开发者角度:合理。不同画像
本文向大家介绍请你从产品角度分析一下拼多多。相关面试题,主要包含被问及请你从产品角度分析一下拼多多。时的应答技巧和注意事项,需要的朋友参考一下 产品优势: 下沉市场用户基数可观,从用户日常高频消费场景入手 主流用户群体的特征,与微信娱乐流量的契合,流量转化率较高,通过每日签到、小游戏等方式每日唤醒用户,提高产品活跃度 以分享砍价、拼团等社交化电商玩法,充分利用了用户的碎片化
本文向大家介绍你如何看待子弹短信?从产品的角度,简要对比分析微信和子弹短信。相关面试题,主要包含被问及你如何看待子弹短信?从产品的角度,简要对比分析微信和子弹短信。时的应答技巧和注意事项,需要的朋友参考一下 1. 产品定位: 子弹短信 定位只是一个通讯工具。 微信 已经从通讯工具泛化为一个包含支付、小程序、公众号生态的平台级应用。 2. 目标用户: 子弹短信 想解决那些日处理消息量非常大的人群的需
问题内容: 我正在创建路径,并使用和在每个路径中添加多行。然后绘制所有路径。但是某些路径中的线之间有1-2个像素的间隔。如何删除这些空格?我的代码是这样的: 问题答案: 也许这会创造你想要的 :)
问题内容: 嗨,我正在尝试创建仿射变换,使我可以将一个三角形变换为另一个三角形。我所拥有的是2个三角形的坐标。你能帮助我吗? 按照亚当·罗森菲尔德的回答,我想出了这段代码,以防万一有人无聊地自己解决方程: 问题答案: 我假设您在这里谈论2D。仿射变换矩阵中有9个值: 有3个顶点输入,和,当其转化应该成为,,。然而,由于我们在齐次坐标的工作,应用到不一定给-它给人的倍数。所以,我们也有未知的乘法器,
本文向大家介绍从2015年起,微博首页信息流的内容从严格时间排序改为智能排序,请你列举一下影响微博智能排序的因素有哪些?并从多角度分析从时间排序变为智能排序给微博带来哪些收益。相关面试题,主要包含被问及从2015年起,微博首页信息流的内容从严格时间排序改为智能排序,请你列举一下影响微博智能排序的因素有哪些?并从多角度分析从时间排序变为智能排序给微博带来哪些收益。时的应答技巧和注意事项,需要的朋友参
本文向大家介绍列举 3 种目前比较热的手机 APP,说明对应类别后并对其进行简要描述(提示:可从目标人群、主要功能特点、使用场合等多种角度进行描述)。最后请分析这些 app 如何能够成为热门 app。相关面试题,主要包含被问及列举 3 种目前比较热的手机 APP,说明对应类别后并对其进行简要描述(提示:可从目标人群、主要功能特点、使用场合等多种角度进行描述)。最后请分析这些 app 如何能够成为热
本文向大家介绍1、注册帐号是使用互联网的重要环节,列出常见的4种帐号注册方式2、从用户角度分析比较各注册方式优缺点,3、从产品角度分析为何部分产品仅允许使用手机号注册。相关面试题,主要包含被问及1、注册帐号是使用互联网的重要环节,列出常见的4种帐号注册方式2、从用户角度分析比较各注册方式优缺点,3、从产品角度分析为何部分产品仅允许使用手机号注册。时的应答技巧和注意事项,需要的朋友参考一下 1、手机