为什么需要异步?
因为基于JavaScript的语言自身的特点: Javascript语言的执行环境是单线程。即一次只能完成一个任务。若有多个任务则需排队逐个执行——前一个任务完成,再执行后一个任务。
为避免和解决这种问题,JS语言将任务执行模式分为异步和同步。同步模式”就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;”异步模式”则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
前端常见的异步操作:
1、回调函数
也就是函数层层嵌套,参考自己文章:搞定callback-hell(回调地狱)、promise 回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。
2、Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了
Promise对象。
两个特点:
- 1)对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变 - 2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的
promise对象简单例子:
function timeOut(ms) {const p = new Promise((resolve, reject) => {setTimeout(resolve, ms, "done");});return p;}timeOut(2000).then(value => {console.log(value); //两秒后打印 deon});
timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。
⚠️: promise新建后会立即执行
let promise = new Promise(function(resolve, reject) {console.log('Promise');resolve();});promise.then(function() {console.log('resolved.');});console.log('Hi!');// Promise// Hi!// resolved
promise异步加载图片的例子:
function loadImg(url) {const p = new Promise((resolve, reject) => {const img = new Image();img.onload = () => {resolve(img);console.log(img.width); //1280};img.onerror = () => {reject(new Error("Could not load image at " + url));};img.src = url;});return p;}const url1 ="https://user-gold-cdn.xitu.io/2020/3/27/1711ae8edcd5b389?imageView2/0/w/1280/h/960/format/webp/ignore-error/1";console.log(loadImg(url1)); //Promise {<pending>}
上面代码中,使用Promise包装了一个图片加载的异步操作。如果加载成功,就调用resolve方法,否则就调用reject方法。
promise对象实现Ajax:
// promise 实现ajax请求function getAjax(url) {const p = new Promise((resolve, reject) => {const handler = function() {if (this.readyState !== "4") {return;}if (this.status === 200) {resolve(this.response);} else {reject(new Error(this.statusText));}};const client = new XMLHttpRequest();client.open("GET", url);client.onreadystatechange = handler;client.responseType = "json";client.setRequestHeader("Accept", "application/json");client.send();});return p;}getAjax("/posts.json").then(function(json) {console.log("Contents: " + json);},function(error) {console.error("出错了", error);});


3、async/await
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖。
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已
