一、为什么JavaScript是单线程?
原因:因为JS是一个脚本语言,它主要是面对于浏览器的用来于用户互动的以及DOM的操作。因此
才决定出它是单线程。如果是多线程,它就会带来复杂的同步问题。所以决定JS是单线程。
二、同步和异步的任务
1、因为js是单线程就会带来一些问题。就是所有任务都会排队,前一个任务完成,后一个任务才能执行
那如果前一个任务耗费时间长,那后面的任务岂不是要一直等待。 于是就出现了两种任务
同步任务:在主线程上排队的任务,只用前一个任务执行完毕,后一个任务才能紧接着执行。
异步任务:先不进入主线程,而是先进入到任务队列,只用任务队列通知主线程任务完成,才能进入到
主线程然后执行完毕。
三 事件和回调函数
1.任务队列就是一个事件的队列,当io设备完成一个任务 ,就在任务队列中添加一个事件,表示相关
的任务异步任务可以进入到主线程当中 。
2.所谓的回调函数就是那些被主线程观其来的代码。异步任务必须指定回调函数。当主线程开始执行
异步任务的时候,就调用对应的回调函数
注:任务队列先进先出
异步任务遇到的问题,以及解决的方案
一、
凡是异步任务,都要使用回调函数,而使用回调函数就会遇到问题那就是"回调地狱"。
而所谓的"回调地狱"就是回调函数中嵌套回调,使代码更加混乱,难懂,以及以后的修改
都会出现问题。
解决方案:
Promise
Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。它起到代理作用(proxy),充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。
例:
const p1 = new Promise((resolve , reject) =>{
//resolve() 表示成功时执行的函数,结果传入其中
//reject() 表示失败时执行的函数
/*
承诺
promise 有三种状态:
pedding 正在执行中
resolve 执行成功
reject 执行失败
*/
//只要在promise中没用调用resolve或者reject去更改状态,那么promise一直处于peeding状态
});
// then里面可以写两个回调函数,第一个回调函数时成功状态时的数据,第二个状态时失败时结束的数据
p1.then(() =>{
}, ()=>{})
Promise.prototype.catch( )
方法是.then(null,rejection)或.then(undefied,rejection)的别名,用于指定发生错误时的回调函数6
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
Promise.prototype.finally( )
finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.prototype.all( )
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()
方法接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
Promise.prototype.race( )
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
Promise.race()
方法的参数与Promise.all()
方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()
方法,将参数转为 Promise 实例,再进一步处理。
下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject
,否则变为resolve
。
async await
语法糖
async function getSrc() {
const al = await ajax('get' ,'./1.json');
// console.log(al);
const src1 = al.src;
const all = await ajax('get' ,src1);
// console.log(all);
const src2 = all.src;
const alll =await ajax ('get',src2);
console.log(alll);
}
getSrc();
宏任务和微任务
一、
ES6规范中,microtask称为jobs,macrotask称为task
宏任务是由宿主发起的,而微任务由JavaScript自身发起
二、
二者的区别:
new Promise((resolve) => { console.log('promise') resolve() }) .then(() => { console.log('then1') }) .then(() => { console.log('then2') })
//当 new Promise 执行时它是同步的
//注释:当代码执行时 先同步在异步 然后微任务 宏任务;
requestAnimationFrame()的使用详解
一、
说明:window.requestAnimationFrame()这个API是浏览器提供的js全局方法,针对动画效果。
异步,传入的函数在重绘之前调用。
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
语法:
window.requestAnimationFrame(callback)
二
requestAnimationFrame与setTimeout的区别:
与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新率是75Hz,那么这个时间间隔就变成了1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。