声明:本文绝大部分内容来自《javascriptx学习指南》
异步的使用的场景:
网络请求,如ajax请求
文件系统操作:读写文件等
刻意的时间延迟功能(比如警告)
js对异步编程的支持的三个不同阶段:
callback:回调
promise:承诺
grenerator:生成器阶段
书上的类比:来理解回调和承诺
在一个人满为患且没有预定机制的餐厅找一个空位子。
此时不需要排队等位,当有位子的时候餐厅会打电话给客户。
这就类似回调:给餐厅工作人员提供一些客户信息,允许他们在有位子的时候通知客户。
这样一来,餐厅可以忙自己的事情,而客户也可以做别的事情;没有人在等其他人吃好。
另一家餐厅也许会给客户一个传呼机,在位子准备好后它就会响。
这更像是一个承诺:餐厅工作人员给客户一个承诺,承诺在有空桌子的时候通知客户。
回调
简单的来说,回调就是一个函数,然后在未来的某个时刻调用它。这个函数本身并没有特别之处:它只是一个一般的javascript的函数。通常,会把这些回调函数提供别的函数,或者将他们设为对象属性(又或者在数组中使用他们,这种较少)。一般来说,回调都是匿名函数。
下面一个简单的例子:
使用setTimeout,这是js的内建函数。
setTimetou(f,time)
document.write(`before timeout:`+new Date()+"<br>");
setTimeout(function(){
document.write(`after timeout:`+new Date+"<br>");
},10*1000);//js内建函数,将指函数的执行推迟指定的毫秒数。这里是1分钟。
document.write(`I happen after set setTimeout!<br>`);
document.write("Me too!");
结果是刚开始页面只显示:
before timeout:Mon Feb 26 2018 09:09:17 GMT+0800 (中国标准时间)
I happen after set setTimeout!
Me too!
等10s:页面只显示
after timeout:Mon Feb 26 2018 09:09:27 GMT+0800 (中国标准时间)
在一般情况下,除非因为编译问题从而不得不给函数命名,通常都会用匿名函数:
setInterval和clearInterval
setInterval是每隔特定时间运行回调函数,并且一直运行下去。
const start = new Date();
let i = 0;
const intervalId = setInterval(function(){
let now = new Date();
document.write(intervalId+"<br>");
if(now.getMinutes() !== start.getMinutes() || ++i>10)
clearInterval(intervalId);
},5*1000)
setInterval返回一个ID,在后面可以用来取消(停止)这个调用的。
scope和异步执行
异步执行:scope和闭包如何影响异步执行?
每当一个函数被调用时,都创建了一个闭包:所有函数内部创建的变量(包括形参)只在有被访问的时候才存在。
<script>
function countdown(){
let i;//成为这个域的变量。所以for循环中的i都是指向一个。
//所以才导致闭包无法保护for里的变量。而下面的let i是在for里面的,他们是同级的。
//所以闭包能保护。暂且这样理解。待深入
console.log("countdown");
for(i=5;i>=0;i--)
{
setTimeout(function(){
document.write(i===0?"GO":i);
document.write("<br>");
},(5-i)*1000);
}
}
countdown();
</script>
这里的输出结果是6个-1
-1
-1
-1
-1
-1
-1
原因:i定义在for循环的外面。for循环执行完毕时,i的值已经为-1,之后callback函数才开始执行。
理解scope和异步执行时如何关联的:当调用 c() 时,创建了一个包含 i 的闭包。所有在for循环中创建的(包括匿名)回调函数都可以访问i,并且是同一个i
function c(){
console.log("countdown:");
for(let i=5;i>=0;i--)//重点:声明在for中
{
setTimeout(function(){
console.log(i===0?"GO":i);
},1000);
};
};
c();
循环的过程时先生成6个setTimeout()
分别是:
i=5,setTimeout(f,0);
i=4,setTimeout(f,1000);
i=3,setTimetout(f,2000);
i=2,setTimeout(f,3000);
i=1,setTimeout(f,4000);
i=0,setTimeout(f,5000);
可以看做是这6个不同的操作都已经放到了相应的时间点上了,就等相应的时间点来临,它就做相应的事。
上面的let i在for循环内外差异的理解的参考:
http://blog.csdn.net/baidu_36831253/article/details/79378819
http://blog.csdn.net/qq_33276399/article/details/73131046
错误优先回调
由于回调使异常处理变的很棘手,所以需要一种更好的方式将错误传到回调。于是就出现了在回调中使用第一个参数来接受错误对象的约定。如果该对象为null或undefined,就表示没有错误。
明天继续。去去看看ajax。异步已经有了一个基本概念。等下ajax还是有不理解,再回来补充。