Promise 依然金字塔,该怎么美化
发布于 8 年前 作者 neechange 4079 次浏览 来自 问答

Promise.all([3,1,5].map(function (row,i) { --return new Promise(function (resolve, reject) { ----setTimeout(function(){resolve(row)},i*100); --}).then(function(row){ ----return new Promise(function (resolve, reject) { ------ //resolve(row+1); ------reject(new Error(‘http 返回状态’)) ----}).then((row)=>{return row+2},(err)=>{err=err||new Error();console.log(http err ${err.message||err});throw new Error(http err: ${err.message||err}...)}) --}).then((row)=>{return row},(err)=>{console.log(wait err ${err.message||err});throw new Error(wait err: ${err.message||err})}); })).then(function(args){console.log(args,ok)}) .catch((err)=>{console.log(Promise.all触发 reject: ${err.message})});

//实为URL列表+HTTP.get请求 每隔1秒请求1个; //写的很丑,3层Promise 3层then //http可以触发Promise.all的reject,然而剩下的timer怎么clear QQ图片20160611000933.png 修改后可以cleartimer了,小伙伴们有没有then递归式的

12 回复

排版惨不忍睹

来自酷炫的 CNodeMD

没法呀 这里支持ACE 还是CodeMirror

用markdown重排一下啊,好难看。。。。

  1. setTimeout和发送请求本身是耦合的,没有必要为了拆开来强行加一层Promise
  2. function() 和 => 混用不好,你完全可以花点时间至少解决这个问题,代码会好读不少,但你太懒,pia!扔给我们
  3. 如果只是为了用row来计数,并且出错的时候取消所有timer,也不需要这么麻烦,我不知道我理解得对不对
  4. HTTP error也不需要重新封装,一般AJAX库的的error object已经包含了所需要的信息
Promise.all(
  [3, 1, 5].map((row, i) => {
    return new Promise((resolve, reject) => {
	  let timer = setTimeout(() => {
		sendHTTPRequest()
			.success((res) => {
				!!window.rows__ ? window.rows__++  : window.rows__ = 0;
				resolve(res);
			}
			.fail((err) => {
				// 此时window.timers__已经建好了,可以立即清除
				window.timers__.forEach((timer) => clearTimeout(timer)); 
				delete window.timers__;
				reject(err));
			} 
	  }, i * 100);
	  (windows.timers__ = window.timers__ || []).push(timer);
    });
  });
)
.then(
	(responses) => { ... }
	(err) => {
		// window.rows__ 
  		// window.timers__.forEach() 也可以放在这里做 
  	}
)

总的来说,碰到这种奇怪的代码,应该先想想有没有必要,而不是假设它有必要了,再试图去用“聪明”的代码方法去解决带啦的问题,能简单为什么不简单呢。

var timers=[],urls=['http://sina.com/list=00001','http://sina.com/list=00002','http://sina.com/list=00003'];
Promise.all(urls.map((url,i)=>{
	return new Promise(function (resolve, reject) {
		let timer=setTimeout(()=>{
			http.get(url,(res)=>{
				var chunks = [],size=0;
				res.on('data',chunk=>{chunks.push(chunk),size += chunk.length});
				res.on('end' ,()=> res.statusCode==200
					?resolve(Buffer.concat(chunks,size).toString())
					:reject("get error statusCode: " + res.statusCode)
				);
			}).on('error',(err)=>{
				reject (`http 第${i}次出错`)
			});
		},i*100);
		timers.push(timer)
	})
})).then(datas=>{
	console.log(`全部返回`,datas)
})
.catch(err=>{
	console.log(`Promise.all err ${err}`);
	timers.forEach(timer=>clearTimeout(timer))
});

setTimeout跟请求放一起确实好看多了

@neechange 这类问题(多个promise)的最优解我个人认为是RxJS (Observable) https://www.delivoper.com/t/rxjs-observable/38 用类似 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/concat.md 然后.subscribe(fn),和Promise不同的是,subscribe中的fn会被执行n此,这样就不要Promise.all()这样的步骤了,代码会更好理解。

就不展开了,有兴趣去看吧。

一些方法可以抽出来,可以有效的减少几层^_^

来自酷炫的 CNodeMD

三层就不行了?我觉得到七八层的时候,你才不能容忍。 Promise 也没有很好的办法进行控制,一但使用 Promise,then 传染到四处。如果你要递归可以使用,直接在 then 中调用你的函数就何以了。现阶段,如果 async/await 不能使用的话,yield 是非常好的选择。你一但学会使用,就觉得世界清静了,回到了没有回调的世界。

@flamingtop 又来一个rxjs,rxjs概念太多,错误处理的方法跟一般的还不一样。学起来很陡峭,不会一但学会,那个爽。话说,你们有在生产环境中使用这个东西吗?对团队要求太高了。

@htoooth 刚开始理解概念需要点耐心,但一旦理解了也还好。做Angular 2开发,RxJS很重要。

@flamingtop 好新潮啊,Angular2 都在使用,团队强大hold得住。

回到顶部