一:JS事件循环
1:同步调用
同步调用是一种阻塞式调用,调用要等待双方执行完毕才返回,他是一种单向调用。
2:回调
回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。
3:异步调用
异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方,比如浏览器点击事件中,用户点击后,会调用JS中的回调函数。
异步的实现原理:
首先左上角的Call stack(调用栈)会把代码一行一行的执行,遇到addEVentListener,也就是事件,那么它不会执行,会托管在implementation-specific(可以理解为浏览器)中,右上角的implementation-specific会把这个事件记下来,当有人点击时,那么它会load成一个消息存放在右下角的message queue中,然后Event Loop(事件循环)会一直在那里循环,查看message queue中的消息,有消息,就把它扔回调用栈,然后执行call back的事件。
二:ES6
阮大大的《ECMAScript入门》 http://es6.ruanyifeng.com/
1: promise
new Promise((resolve, reject) => { console.log('begin promise') setTimeout(resolve, 1000) }).then(() => { console.log('over') })
这个是非常简单的代码,先new promise传入2个参数,resolve代表成功会怎么样,reject代表失败会怎么样,上面的代码的意思是先输出'begin promise'resolve成功后1秒后输出'over'。then()的意思是resolve之后立即执行。
new Promise((resolve,reject)=>{ console.log('begin') setTimeout(function() { resolve(); },1000); }).then(()=>{ console.log('1') return new Promise((resolve,reject)=>{ setTimeout(function() { resolve(); },1000); }); }).then(()=>{ console.log('2'); return new Promise((resolve)=>{ setTimeout(function(){ resolve(); }, 1000) }) }).then(()=>{ console.log('over'); })
代码依次执行后会出现'begin',1,2,'over'。
return new Promise的意思就是返回一个new promise, 放在上一个promise对象上,形成链式调用,新的promise就代表this的上下文,与上面的promise形成相同的结果。
,我们发现整一个过程就像一个瀑布流一样,但是它都嵌套在一起了。非常的不友好。
2:thunk/curry化函数
thunkAsync = thunkify(async)
thunkAsync(params)(callback)
var Thunkify = function(fn){ return function(){ var args = Array.prototype.slice.call(arguments); return function(callback){ //2000,callback args.push(callback); return fn.apply(this,args) } } } var thunkTimeout = Thunkify((time,callback)=>{ setTimeout(callback, time) }) //thunkTimeout(time)(callback) thunkTimeout(2000)(()=>{ console.log('success'); })
thunkify的意思:先传入一个元素setTimeout(),但是它没有被立即调用,是先放在了这里,然后有返回了一个函数,返回的这个函数是把arguments里面的东西存起来,有就是2000,然后又返回一个函数,这个返回函数传入的才是最终的callback,在这个函数中有把callback push给了args,那么args的状态就是2000,callback,然后最后一个return就是进行一开始我们保存的setTimeout的调用。
3:generator
function* helloGenerator(){ console.log('generator'); yield 'world' console.log('finish') } // //执行generator var generatorResult = helloGenerator(); console.log(generatorResult.next().value);
console.log(generatorResult.next());
generator要记住2点,next和yield,我们可以通过next()来控制yield的执行。next是继续执行,yield是暂停。
var gen = function* (){ //把刚才的thunk函数拿过来,放在yield的后面 //只需要接着传一个callback就可以执行了 var r1 = yield thunkTimeout(2000); console.log(r1); //把刚才的thunk函数拿过来,放在jield的后面 //只需要接着传一个callback就可以执行了 var r2 = yield thunkTimeout(2000); console.log(r2) } //这是一个手动执行的版本 var g = gen(); //这个value指向的是,刚才我们已经传入的setTimeout(2000) g.next().value(function(){ //这个function就是我们的callback //在i这里,已经完成了第一个setTimeout的过程 var r2 = g.next('the first function complete'); //这里的value,指向的是第二个setTimeout(2000) r2.value(function(){ //完全的执行 g.next('the second function complete'); }) })
三:异步优化
//像这样才能向上面那样2秒2秒的执行 setTimeout(function(){ console.log('the first function complete') setTimeout(function(){ console.log('the second function complete') }, 2000) }, 2000)
我们要想实现上面的效果,有不想一直的嵌套。怎么办?
//thunk/curry化函数 var Thunkify = function(fn){ //传入一个functuion:setTimeout //这个function fn,没有被立即调用,而是被放在了这里,先不管 //返回了另一个函数 return function(){ //把arguments里面的东西存了起来,2000 var args = Array.prototype.slice.call(arguments); //又返回了一个新的函数 //这个函数传入的,才是最终的callback return function(callback){ //完成push以后,args的状态是什么 //2000,callback args.push(callback); //最终在进行一开始我们保存的setTimeout的调用 return fn.apply(this,args) } } } var thunkTimeout = Thunkify((time,callback)=>{ setTimeout(callback, time) }) var gen = function* (){ //把刚才的thunk函数拿过来,放在jield的后面 //只需要接着传一个callback就可以执行了 var r1 = yield thunkTimeout(1000); console.log('the first function1 complete'); var r2 = yield thunkTimeout(2000); console.log('the first function2 complete'); var r3 = yield thunkTimeout(3000); console.log('the first function3 complete'); var r4 = yield thunkTimeout(4000); console.log('the first function4 complete'); var r5 = yield thunkTimeout(5000); console.log('the first function5 complete'); } function run(gen){ //第一次把generator执行 var g = gen(); function nextRun(r){ //在第一个行进行了一次next var next = g.next(r); if(next.done == true){ return; } if(typeof next.value.then == 'function'){ //promise要加一个then,才执行,所以这里加一个判断 next.value.then(nextRun) }else{ //第一次value next.value(nextRun) } } nextRun(); } run(gen);
run函数就是用了递归,递归简单点来说,就是自己调用自己。
OK,大功告成。我好像还是第一次写这么认真的博客。