JS是一个富含回调的语言,最近在ajax和弹窗的问题上(之前在Node项目中读取文件和运行sql中也遇到过这种问题)遇到了JS进程无法阻断的问题
问题:依赖函数返回值进行下一步的操作
- 例如datagrid的onBeforeSave这种依赖onBeforeSave的返回值来判断是否继续执行下边的save操作,如果这个返回值需要发送Ajax根据返回值来判断的话,或者需要根据用户输入来判断true或者false的情况下,就GG了
- node运行sql的时候,突发奇想把sql运行封装成一个方法,调用的时候传进去SQL语句然后函数返回值为sal结果。这时候SQL的运行是异步的,导致返回值一直为空
- ajax在这种情况下会被强制的改成同步,这样的修改是负优化,然后还会造成外部变量无法释放,为什么呢
function returnAjax(){
let results = [];
$.ajax({
'url': '.....',
'type': 'post'
'aysn': false,
'success': function (re){
results = re; //外部引用类型变量的引用,妈的
}
})
return results;
}
解决:异步编程
上来就是高大上的异步编程,说白了,要不就是回调,要不就是事件监听(订阅者模式,我是这么理解的),说明白一点,JS在浏览器里是不能进行进程阻断的(然而实际情况上是可以的)
之前考虑到使用while-true,例如下边这么写
function hinahina(){
let results = [];
let isEndAjax = false;
$.ajax({
'url': '.....',
'type': 'post'
'success': function (re){
results = re;
isEndAjax = true;
}
});
while(!isEndAjax){
//... 阻断中
}
return results;
}
像这样的方式阻断就是自杀,因为知道程序进入了这个while,就会一直占据着线程,ajax执行完成后的回调根本没有机会执行
所以只有浏览器中那些BOM的弹窗方法(window对象下挂的那些alter的)会阻断js线程。所以异步改同步,走不通啊
- 第一种:回调
回调,没什么可说的,闭包什么的性能问题和引用类型传参的问题后边再说吧(另起一篇)
- 第二种:promise
第二种就把伟大ES6的promise摆上来,不按套路出牌,是因为我觉得啊,promise跟回调没什么区别,摆一个例子出来:
class MyPromise {
constructor() {
this.callbacks = [];
console.log('构建新的异步对象!');
}
resolve(result) {
this.complete('resolve', result);
}
reject(result){
this.complete('reject', result)
}
complete(type, result) {
while (this.callbacks[0]) {
this.callbacks.shift()[type](result);
}
}
then(successHandler, failedHandler){
this.callbacks.push({
resolve: successHandler,
reject: failedHandler
});
return this;
}
}
然后怎么使用呢
let mp = new MyPromise();
let delay1 = () => {
setTimeout(() => {
console.log(111);
mp.resolve('111执行!');
});
return mp;
};
delay1().then(function (msg) {
console.log(msg)
});
看的出来,每个delay扔回一个promise实例,然后.the会把参数中的方法推到promise实例的callbacks执行队列里,然后当这个实例执行resolve的时候(或者执行reject),才会执行.then穿进去的方法。
感觉就像先把回调写好,然后等着异步执行这个回调。
- 第三种:订阅者
为什么把 “发布/订阅” 放在这,因为看完promise再看 “发布/订阅” 就更好理解了,先写好订阅(类似于先写好回调),然后再在异步执行的代码里进行发布(类似于promise的resolve啥啥的),这样看就和promise一样了。
下面粘上阮的例子,jquery有类似的框架
jQuery.subscribe("done", f2); // 订阅
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done"); // 发布
}, 1000);
}
- 第四种:事件监听
事件监听,这就是js的异步操作体现在事件驱动上了,其实看起来也类似 “发布/订阅” ,先定义一个事件(类似订阅),然后trigger这个事件(类似发布)
还是阮的例子:
f1.on('done', f2);
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}
这样看来 所有的事件绑定和触发 都是一个异步操作。
总结
总体来看,还是没有解决类似onBeforeSave这种限制在操作之前的事件回调,这种依赖onBeforeSave的返回值来判断是否执行下一步操作的情况下,onBeforeSave中绝对不能出现异步的操作。类似返回异步操作结果的方法也不能使用了(node运行sql)所以说老老实实用回调,不要过度依赖返回值
对于commonJS的规范,AMD CMD的规范在另一篇中写。