一、Promise
解决的问题
- 回调地狱问题
- 可读性问题
- 信任问题(也称控制反转问题)
二、回调地狱问题
- 什么是回调地狱呢?笔者认为,异步的嵌套可称之为
回调地狱
,举个栗子🌰//queryData向后端请求数据 queryData('data1', function(ret) { console.log(ret);   queryData('data2', function(ret) { console.log(ret); queryData('data3', function(ret) { console.log(ret); }); }); });
- 回调地狱有哪些问题呢?很典型的两个问题就是
可读性问题
和信任问题
,下面就此两点着重展开。
三、可读性问题
- 可读性问题可想而知,如果你看到的代码是这个样子的,是不是会疯掉
queryData('data1', function(ret) { console.log(ret);   queryData('data2', function(ret) { console.log(ret); queryData('data3', function(ret) { console.log(ret); queryData('data4', function(ret) { console.log(ret);   queryData('data5', function(ret) { console.log(ret); queryData('data6', function(ret) { console.log(ret); //此处省略无数嵌套 }); }); }); }); }); });
- 通过
promise
,可以极大程度上的提高可读性queryData('data1') .then((ret) => { console.log(ret); return queryData('data2'); }) .then((ret) => { console.log(ret); return queryData('data3'); }) .then((ret) => { console.log(ret); return queryData('data4'); })
四、信任问题
- 为什么会产生信任问题呢?
很多时候,我们在开发中都需要依赖大量的三方库,在使用三方库的某些方法时,我们会给三方库传入回调函数,但这些三方库是否百分之百可靠? 或者说,这些三方库是否能够按照我们的设想,在正确的时间正确地调用回调? 这些问题我们不得而知。类似还会出现一些问题:
- 回调过早/过晚/没有回调
- 回调次数过多/过少
- 等等
异步嵌套
带来信任问题的根源在于控制反转
,控制反转
在面向对象中的应用是依赖注入
,比如AngularJS
,Nest
等都实现了依赖注入
。但是在回调中就难以控制,我们将回调传给三方,由三方决定回调的时间以及如何调用回调。举个栗子🌰:ajax( "/rest/user/1", function response(res){ if (res) { userHandler(); } else { nouserHandler(); } }); //假设ajax是一个信任度极低的三方库,repsonse的调用完全由它决定,此刻你是不是菊花一紧
promise
的出现很好地解决了这个问题,promise
并没有取消控制反转,而是把反转出去的控制再次反转,将最终控制权放在自己手中。
promise
与普通回调函数的区别在于,普通回调函数将回调完完全全交给三方,控制权在第三方,而在promise
中,回调只负责通知决议
, 而决议
后的操作则放在then
中,由promise
精确控制。举个栗子🌰
对于回调过早问题, 因为Promise((rs, rj) => { ajax( "/rest/user/1", function response(res){ if (res) { rs(res); } else { rj(); } }); }) .then((res) => { userHandler(res); },()=>{ nouserHandler(); }); // userHandler()和nouserHandler()的调用由promise控制,回调函数仅仅进行了决议
promise
是异步的,所以不会出现异步的同步调用,即使在决议
之前出现错误,错误也会是异步的,所以不会存在回调过早问题。
对于回调过晚问题和没有回调的问题, 因为promise
一旦决议了,就会执行相应的回调,所以不会存在回调过晚或者没有回调的问题。
对于回调次数过多或者过少的问题, 由于promise
只能被决议一次,且决议后无法改变决议结果,所以不会出现回调次数的问题。
参考资料: