什么是异步?
异步与同步是相反的
简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。
什么时候用异步编程
在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。
现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。
为了解决类似这种问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。
回调函数
回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。
例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>回调</title> </head> <body> <button>点击</button> <p></p> <script> var btn = document.querySelector('button'); function fn1(){ btn.onclick = function(){ document.querySelector('p').innerHTML = '我出现了!' } } setTimeout(fn1,1000) </script> </body> </html>
它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等待 1 秒,然后执行回调函数 "fn1",在命令行输出 "我出现了!"。
Promise 的使用
Promise有三种状态:pending=>resolved => rejected
语法格式:
new Promise(function (resolve, reject) { }); const p1 = new Promise((resolve,rejuct)=>{ // throw new Error }) console.log(p1);
默认状态为pending
const p1 = new Promise((resolve, rejuct) => { resolve(); }) console.log(p1);
默认状态为fulfilled等同于resolved
const p1 = new Promise((resolve, rejuct) => { rejuct(); }) console.log(p1);
状态为 rejected
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"); });
这段打印结果为:
.then() .catch() 和 .finally() 三个方法
这三个方法的参数都是一个函数,
.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,
.catch() 则是设定 Promise 的异常处理序列,
.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:
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。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作,这一点从刚才的计时器的例子中可以看出来。
reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常。
但是请注意以下两点:
resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。