JavaScript异步编程
异步
异步(async)是与同步相对的概念。传统的单线程编程中,程序的运行是同步的。同步并不意味着所有的步骤同时运行,而是指步骤在一个控制流中顺序执行。而异步相反,不保证同步,一个异步过程的执行不再与原有的序列有顺序关系。
简单来说,你的代码顺序是什么样,同步就按顺序来;而异步不按顺序来,从主线程发送一个子线程完成任务效率更高。如下图所示:
主线程是单一线程,不能同时接受多方面的请求,所以当一个事件没有结束时,无法同时处理其他请求。因此我们常常用子线程来完成一些可能消耗时间长、以至于被用户所察觉的事件,比如读取一个大文件或者发出一个网络请求。
子线程特点:
- 独立于主线程,即使出现堵塞也不会影响主线程的运行;
- 一旦发射之后就与主线程失去同步,无法确定结束事件,无法处理结束之后需要进行的一系列操作。例如来自服务器的信息,我们无法将其合并到主线程中去。
回调函数
由于子线程的一系列特性,JavaScript的异步操作通常通过回调函数实现异步任务的结果处理。
比如当我们启动一个异步任务时,告诉子线程完成这个任务之后该做什么。如此一来,主线程就不用关心异步任务的状态。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<p>回调函数等待 3 秒后执行。</p>
<p id="demo"></p>
<script>
function print() {
document.getElementById("demo").innerHTML="learn more!";
}
setTimeout(print, 3000);
</script>
</body>
</html>
该段程序主线程运行第一个p标签内容等,子线程运行setTimeout
,是一个消耗时长三秒的过程,第一个参数时回调函数,第二个参数是毫秒数。子线程等待三秒后执行回调函数print
,命令行输出learn more!
需要注意的是:在setTimeout
执行之后,主线程并没有停止!!
AJAX
AJAX:Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
AJAX是一种使用现有标准的新方法,可以在不重新加载整个页面的情况下,与服务器交换数据并异步更新部分网页内容。
占坑补充。。。。。。
JavaScript Promise
Promise是ES6提供的类,目的是更加优雅的书写复杂的异步任务。
新建Promise
new Promise(function(resolve, reject){
//to do
});
对于多次调用异步函数,如第一次间隔1秒,第二次间隔4秒,第三次间隔3秒:
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
}, 3000);
}, 4000);
}, 1000);
以上程序看起来十分累赘,对于更加复杂的异步程序而言就变得更加繁琐了。使用Promise实现同样的功能:
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("First");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("Second");
resolve();
}, 4000);
});
}).then(function () {
setTimeout(function () {
console.log("Third");
}, 3000);
});
Promise的使用
new Promise(function(resolve, reject){
//to do
});
Promise构造函数只有一个参数,是一个函数。这个函数在构造之后会被异步执行,称为起始函数。它包含两个参数,resolve
和reject
,调用resolve表示一切正常,reject是出现异常时调用的。
new Promise(function (resolve, reject) {
var a = 0;
var b = 1;
if (b == 0) reject("Divide zero");
else resolve(a / b);
}).then(function (value) {
console.log("a / b = " + value);
}).catch(function (err) {
console.log(err);
}).finally(function () {
console.log("End");
});
输出结果为:
a / b = 0
End
Promise类有三个方法,它们的参数都是一个函数:
- .then()可以将自己参数中的函数添加到当前Promise的正常执行序列,其传入的参数会按顺序依次执行,有任何异常都会跳到catch序列;
- .catch()设定Promise的异常处理序列;
- .finally()在Promise执行最后一定会执行的序列。
实例:
new Promise(function (resolve, reject) {
console.log(1111);
resolve(2222);
}).then(function (value) {
console.log(value);
return 3333;
}).then(function (value) {
console.log(value);
throw "An error";
}).catch(function (err) {
console.log(err);
});
输出:
1111
2222
3333
An error
resolve()
中可以放置一个参数用于向下一个then传递值,then中的函数也可以返回一个值传递给then;reject()
传递一个异常给之后的catch
函数处理异常。
注意:
- resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
- resolve 和 reject 并不能够使起始函数停止运行,别忘了 return;
- then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。