异步
认。
如果我们要取消事件,浏览器会询问用户是否确定。
readyState
如果我们在文档加载完成之后设置 DOMContentLoaded 事件处理程序,会发生什么?
很自然地,它永远不会运行。
在某些情况下,我们不确定文档是否已经准备就绪。我们希望我们的函数在 DOM 加载完成时执行,无论现在还是以后。
document.readyState 属性可以为我们提供当前加载状态的信息。
有 3 个可能值:
loading —— 文档正在被加载。
interactive —— 文档被全部读取。
complete —— 文档被全部读取,并且所有资源(例如图片等)都已加载完成。
所以,我们可以检查 document.readyState 并设置一个处理程序,或在代码准备就绪时立即执行它。
异步
异步解决方案
同步操作:顺序执行,同一时间只能做一件事情。缺点是会阻塞后面代码的执行。
异步:指的是当前代码的执行作为任务放进任务队列。当程序执行到异步的代码时,会将该异步的代码作为任务放进任务队列,而不是推入主线程的调用栈。等主线程执行完之后,再去任务队列里执行对应的任务。优点是:不会
阻塞后续代码的运行。
异步场景
定时任务:setTimeout、setInterval 网络请求:ajax请求、动态创建img标签的加载
事件监听器:addEventListener
回调
回调函数就是我们请求成功后需要执行的函数。
实现了异步,但是带来一个非常严重的问题——回调地狱。
事件发布/订阅
Promise
const promise = new Promise((resolve, reject) => {
.then((arg) => { console.log(`执行resolve,参数是${arg}`)
})
.catch((arg) => { console.log(`执行reject,参数是${arg}`)
})
.finally(() => { console.log('结束promise')
});
Promise.reject(2)
//.catch(err=>console.log("err1,",err))
.then(null, err => console.log("err1,", err)) //因为是rejected状态,执行then的第二个 callback,改变状态为fulfilled
.then(res => { console.log("then1", res)
}, null) //因为是fulfilled,于是执行第一个回调,不会去到下一步catch
//.catch(err=>console.log("err2,",err))
.then(null, err => console.log("err2,", err))
then实现链式操作减低代码复杂度,增强代码可读性。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。
每个Promise都会经历的生命周期是:
进行中(pending) - 此时代码执行尚未结束,所以也叫未处理的(unsettled)
已处理(settled) - 异步代码已执行结束已处理的代码会进入两种状态中的一种:
已完成(fulfilled) - 表明异步代码执行成功,由resolve()触发已拒绝(rejected)- 遇到错误,异步代码执行失败,由reject()触发
方法
- Promise.all 传入多个异步请求数组,若all成功,进入fulfilled状态,若一个失败,则立即进入rejected状态。
- Promise.allSettled 传入多个异步请求数组,无论失败还是失败,都会进入fulfilled状态。
- Promise.race 以一个Promise对象组成的数组作为参数,只要当数组中一个Promsie状态变成resolved或者
rejected时,就调用.then方法。
事件循环
iterator中文名叫迭代器。它为js中各种不同的数据结构(Array、Set、Map)提供统一的访问机制。部署了 Iterator接口,就可以完成遍历操作。因此iterator也是一种对象,不过相比于普通对象来说,它有着专为迭
代而设计的接口。
iterator 的作用:
为各种数据结构,提供一个统一的、简便的访问接口;
使得数据结构的成员能够按某种次序排列;
ES6 创造了一种新的遍历命令for…of循环
iterator的结构:它有next方法,该方法返回一个包含value和done两个属性的对象(我们假设叫 result)。value是迭代的值,后者是表明迭代是否完成的标志。true表示迭代完成,false表示没有。iterator内部
有指向迭代位置的指针,每次调用next,自动移动指针并返回相应的result。
原生具备iterator接口的数据结构如下:
Array Map
Set String
TypedArray 函数里的arguments对象
NodeList对象
这些数据结构都有一个Symbol.iterator属性,可以直接通过这个属性来直接创建一个迭代器。也就是说, Symbol.iterator属性只是一个用来创建迭代器的接口,而不是一个迭代器,因为它不含遍历的部分。使用
Symbol.iterator接口生成iterator迭代器来遍历数组的过程为:
let arr = ['a','b','c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
for ... of的循环内部实现机制其实就是iterator,它首先调用被遍历集合对象的 Symbol.iterator 方法,该方法返回一个迭代器对象,迭代器对象是可以拥有.next()方法的任何对象,然后,在 for ... of 的每次循环中,都将调用
该迭代器对象上的 .next 方法。然后使用for i of打印出来的i也就是调用.next方法后得到的对象上的value属性。
对于原生不具备iterator接口的数据结构,比如Object,我们可以采用自定义的方式来创建一个遍历器。
yield 1;
yield 2;
yield 3;
}
// generators可以像正常函数一样被调用,不同的是会返回一个 iterator let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
Generator 函数是一个普通函数,但是有两个特征:
function关键字与函数名之间有一个星号使用yield语句,定义不同的内部状态
Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象
(Iterator Object)
function* generator() {
yield 1;
}
console.dir(generator);
generator函数的返回值的原型链上确实有iterator对象该有的next,这充分说明了generator的返回值是一个 iterator。除此之外还有函数该有的return方法和throw方法。
generator和普通的函数完全不同。当以function*的方式声明了一个Generator生成器时,内部是可以有许多状态的,以yield进行断点间隔。期间我们执行调用这个生成的Generator,他会返回一个遍历器对象,用这个对象上的方
法,实现获得一个yield后面输出的结果。
yield和return的区别:
都能返回紧跟在语句后面的那个表达式的值 yield相比于return来说,更像是一个断点。遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而
return语句不具备位置记忆的功能。
一个函数里面,只能执行一个return语句,但是可以执行多次yield表达式。
正常函数只能返回一个值,因为只能执行一次return;Generator 函数可以返回一系列的值,因为可以有任意多个yield
yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号。
使用Generator的其余注意事项:
需要注意的是,yield 不能跨函数。并且yield需要和*配套使用,别处使用无效
function* createIterator(items) {
items.forEach(function (item) {
// 语法错误 yield item + 1;
});
}
箭头函数不能用做 generator
那么Generator到底有什么用呢?
因为Generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。
Generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码
async/await
ES7提出的关于异步的终极解决方案
第一个版本说async/await是Generator的语法糖第二个版本说async/await是Promise的语法糖
关于async/await是Generator的语法糖:表明的就是aysnc/await实现的就是generator实现的功能。但是 async/await比generator要好用。
因为generator执行yield设下的断点采用的方式就是不断的调用iterator方法,这是个手动调用的过程。
针对generator的这个缺点,后面提出来自动执行next,但是仍然麻烦。而async配合await得到的就是断点执行后的结果。
因此async/await比generator使用更普遍。
async函数对 Generator函数的改进:
- 内置执行器:Generator函数的执行必须靠执行器,因为不能一次性执行完成。但是,async函数和正常的函
数一样执行,也不用使用 next方法,会自动执行。
- 适用性更好:yield命令后面是 Promise对象,但是 async函数的 await关键词后面,可以不受约束。
- 可读性更好:async和 await,比起使用 *号和 yield,语义更清晰明了。
关于async/await是Promise的语法糖:如果不使用async/await的话,Promise就需要通过链式调用来依次执行 then之后的代码:
而async/await的出现,就使得我们可以通过同步代码来达到异步的效果:
全站分卷索引 · 154 卷
- 1代码随想录知识星球精华(最强八股文)第五版(前端篇))
- 2html语义化
- 3src 和 href 的区别
- 4link 与 @import 的区别
- 5iframe
- 6CSS
- 7伪元素和伪类
- 8block,inline,inline-block
- 9重排、重绘和合成
- 10盒子模型
- 11margin 合并
- 12margin和padding 的值为百分比时
- 13浮动
- 14定位
- 15CSS选择器
- 16CSS选择器优先级
- 17选择器权重Specificity
- 18CSS属性继承
- 19不可/可继承属性
- 20display: none与 visibility: hidden的区别
- 21background-size
- 22client、offset&scroll
- 23CSS3新特性
- 24flex布局
- 25常见布局
- 26三栏布局
- 27垂直居中
- 28水平垂直居中
- 29CSS画三角形
- 30使chrome支持12px以下文字
- 31响应式布局
- 32媒体查询
- 33过渡与动画
- 34JavaScript 动画 和 CSS动画
- 35SCSS
- 36CSS性能优化
- 37有哪些数据类型
- 38判断数据类型
- 39类型转换
- 40parseInt&parseFloat
- 41浮点数求和步骤
- 42十进制小数转二进制
- 430.1+0.2 为什么不等于 0.3
- 44undefined 和 undeclared 的区别
- 45JavaScript NaN 属性
- 46isFinite()&isNaN()
- 47数组
- 48对原数组有影响
- 49对原数组无影响
- 50数组去重
- 51数组拍平
- 52ES6新增的数组方法
- 53判断是否存在某个值
- 54arguments为啥不是数组
- 55对象
- 56遍历对象的方法
- 57判断对象是否具有属性
- 58for in 和 for of 的区别
- 59继承方式
- 60instanceof
- 61深浅拷贝
- 62freeze属性
- 63函数
- 64函数柯里化
- 65函数的 length
- 66箭头函数和普通函数区别
- 67构造函数
- 68执行上下文
- 69作用域
- 70作用域和作用域链
- 71闭包和内存泄漏
- 72this
- 73关于 this 的指向问题
- 74改变this指向的方法(bind / call / apply)
- 75字符串
- 76DOM和事件
- 77哪些事件支持冒泡
- 78阻止冒泡
- 79HTMLCollection、NodeList
- 80dom.onclick 和 dom.addEventListener的区别
- 81e.target和e.currentTarget
- 82页面生命周期
- 83异步
- 84内存管理GC
- 85其它
- 86JavaScript 中日期时间格式转换
- 87input和object实现双向绑定
- 88JSON.stringify()
- 89escape、encodeURI&encodeURIComponent
- 90移动端滚动穿透和溢出
- 91ES6
- 92Map字典
- 93... 与rest
- 94proxy
- 95模块化
- 96Ajax、Fetch和Axios
- 97Webpack
- 98浏览器:事件循环
- 99浏览器内核
- 100浏览器同源策略
- 101输入URL回车后发生了什么
- 102HTTP
- 103HTTP 2.0
- 104浏览器存储
- 105鉴权
- 106Webstorage
- 107浏览器执行机制
- 108AST 抽象语法树
- 109性能优化
- 110CSS
- 111网络相关
- 112使用HTTP2.0
- 113图片
- 114CDN图片
- 115其他文件优化
- 116降低APP首页开屏渲染时间
- 117页面白屏
- 118HTTPS中间人攻击
- 119Web Worker
- 120Service Worker
- 121微前端
- 122Vue
- 123v-show 和 v-if 的区别
- 124双向数据绑定的原理
- 125Vue中的插槽使用
- 126Vue中的key
- 127Vue过滤器
- 128Vue中Scoped原理
- 129Vue中$nextTick的使用
- 130Vue中实现组件通信的方式
- 131Vue-router
- 132Vue路由传参
- 133前端路由
- 134Vuex
- 135虚拟DOM
- 136DIFF 算法
- 137Vue3和Vue2有哪些区别
- 138说一说你对React的理解
- 139React事件机制
- 140说一说你对react refs的理解
- 141react中key的作用
- 142组件开发
- 143有状态组件和无状态组件
- 144函数式组件和类组件的区别
- 145PureComponent&Component
- 146常见 Hooks
- 147状态管理
- 148redux toolkit
- 149React18新特性
- 150client中的createRoot取代以前的ReactDOM.render
- 151Suspense
- 152新的Hooks
- 153VDom一定更快吗
- 154Fiber