1.JS是单线程,但是为什么是单线程呢?
因为我们需要能够通过操作DOM方式,为了防止DOM冲突【假设JS是多线程,那么它可以同时执行多个任务,如果这多个任务都是操作DOM,也就是说可能存在多种不同的DOM操作,而且这些操作同时执行】,所以必须把JS设置成单线程。
异步任务在单线程中是事件轮询通过回调的方式来实现的。
2.事件轮询是什么?
浏览器通过JS脚本执行,JS脚本中执行任何任务有个叫调用栈(call Stack)的东西,所有任务都放Call Stack中,异步任务直接在Call Stack调用,调用完放Web APIs中,比如setTimeout,几秒后,把里面的回调函数放到CallBack queue中,当Call Stack里面为空,轮询机制就往CallBack queue中查看有没有任务,有执行。如此反复。
题目:
console.log('hi')
setTimeout(function cb1(){
console.log('cb1');
},5000)
console.log('bye');
顺序:
1.
2. setTimeout放进去,然后开启一个计时器timer,Call Stack清空,计时结束后,把cb1 放到Callback队列中,然后通过事件轮询方式,cb1放到Call Stack,再执行逻辑
3.打印console.log('bye')
顺序就是:hi bye cb1
3.什么是回调函数?
参数是函数的函数是回调函数,比如
arr.sort(function(a,b){} ),参数是回调函数。常见的回调函数有setTimeout(function(){})、$ajax({ success:function(){} })等。
但是回调函数不一定都是异步函数。存在同步回调函数和异步回调函数。计数器执行完后才执行这个方法,ajax也是成功后才执行,所以他们都是异步回调函数。sort里是同步回调函数。
4.迭代和遍历有什么区别?
迭代:从目标源依次逐个抽取的方式提取数据
遍历:只要循环所有数据就行
迭代:
function myIterator(arr){
var index=0;
return{
next(){
if(index<arr.length){
return{
value:arr[index++],done:false
}
}
return { value:undefined,done:true };
}
}
}
生成器【function *】是为了生成迭代器。——解决对象没有symbol.iterator属性的问题【不能用for of遍历对象】
yield能中断函数的执行:
function* test(){
console.log(1);
yield 1;
console.log(2)
}
var item=test();
console.log(item.next());
function* test(){
let value1=yield 1;【传值方式是红色箭头】
console.log(value1);---‘two’
let value2=yield 2;
console.log(value2);
}
var ite=test();
console.log(ite.next('one'));
console.log(ite.next('two'));
async函数本质上是 生成器函数+执行器函数【就是让value1接收yield1的值】
Promise
Promise有三个状态pending进行中、fulfilled已完成、rejected已失败,两个阶段:pending到fulfilled和pending到rejected
通过resolve()改变状态pending到fulfilled,通过reject()把状态从pending改成rejected
function readFile(pathname){
return new Promise(function (resolve,reject){
fs.readFile(pathname,'utf-8',function(err,data){
if(err){
reject(err);
return;
}
resolve(data);
});
})
}
let promise=readFile('./name.txt');
promise.then(function(data){-----------如果成功就会把上面resolve(data)的data传进这里,且执行
},function(err){-----同理
})
总结:1.promise状态不受外界影响
2.状态一旦改变就不能更改
let promise=new Promise(function(resolve,reject){
console.log('promise');
resolve('resolve');//微任务,优先执行微任务
})
setTimeout(function(){//异步任务
console.log('timeout');
},0);
promise.then(function (data){
console.log(data);
})
console.log('hi');
打印结果:
promise
hi
resolve
timeout
let p1=Promise.resolve(1);
let p2=Promise.reject(2);
p1.then(function(data){
console.log(data);
})
// p2.then(function(){
// },function(err){
// console.log('err'+err);
// })
p2.catch(function(err){
console.log('err'+err);
})
打印:
1
err2
thenable对象
let obj={
then(resolve,reject){
reject(11);
}
}
let p1=Promise.resolve(obj);----当绑定一个参数为thenable对象时,会默认调用对象的then方法。
p1.then(function(data){
console.log(data);
},function(err){
console.log('err'+data);---输出err11
})
let obj={
then(resolve,reject){
reject(11);
}
}
let p1=Promise.reject(obj);----在reject不会调用
p1.then(function(data){
console.log(data);
},function(err){
console.log('err'+data);
})
Promise.resolve().then()(function(){
console.log('promise1');
setTimeout(()=>{
console.log('setTimeout2');
},0)
})
setTimeout(()=>{
console.log('setTimeout1');
Promise.resolve().then()(function(){
console.log('promise2');
})
},0);
输出:
promise1
setTimeout1
promise2
setTimeout2
链式调用
let p1=new Promise((resolve,reject)=>{
resolve(1);
})
p1.then(res=> res+1 )
.then(res=> res+1)
.then(res => { console.log(res+1) ;return res+1})-------输出4
let p1=new Promise((resolve,reject)=>{
resolve(1);
reject(10);
})
p1.then(res=> console.log(res))-----输出1
.then()
.then()
.then(res=> console.log(res))----输出undefined
.catch(err =>console.log(err))
状态依赖
当存在状态依赖,自身状态就会无效。
const p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('1000');
},2000)
})
const p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(p1);----这里的状态无效,由依赖p1决定,p1成功它就成功,反之同理
},1000)
})
p2.then(res => console.log(res))
.catch(err =>console.log(err));---输出1000
Promise.all 和Promise.race
all:等最慢的,必须所有都是true(resolve)
race:找最快的,如果最快的是reject,那就执行.then的第二个函数
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(10)
},1000)
})
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(20)
},2000)
})
let p3=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(30)
},3000)
})
let p4=Promise.all([p1,p2,p3]);---所有的promise都拿到结果后,p4才会拿到最终结果
p4.then(res=>{
console.log(res);
})
asycn和await
async函数本质上是 生成器函数+执行器函数
async function readSync(){
let value1=await readFile('./name.text','urf-8');
let value2=await readFile(value1,'utf-8');
let value3=await readFile(value2,'utf-8');
return value3;
}
let promise1=readSync();
promise1.then(function(res){
console.log(res);
})
如果asycn定义的函数有返回值xxx,就相当于resolve(xxx):
async function demo01() {
return 123;
}
demo01().then(val => {
console.log(val);// 123
});
如果没有返回值,相当于resolve()
async function demo01() {
console.log("withOut return")
}
demo01().then(val => {
console.log(val);// undefined
});
如果 await 的是 promise对象,await 会暂停 async 函数内后面的代码,先执行 async 函数外的同步代码(注意,promise 内的同步代码会先执行),等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果返回后,再继续执行 async 函数内后面的代码
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(' enough sleep~');
}, second);
})
}
async function awaitDemo() {
let result = await sleep(2000);
console.log(result);// 两秒之后会被打印出来
}
console.log("主线程1")
awaitDemo();
console.log("主线程2")
//主线程1
//主线程2
//enough sleep~
如果 await 的不是一个 promise ,而是一个表达式。await 会暂停 async 函数内后面的代码执行,先执行 async 函数外的同步代码(注意,此时会先执行完 await 后面的表达式后再执行 async 函数外的同步代码)
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(' enough sleep~');
}, second);
})
}
function normalFunc() {
console.log('normalFunc');
}
async function awaitDemo() {
await normalFunc();
console.log('something, ~~');
let result = await sleep(2000);
console.log(result);// 两秒之后会被打印出来
}
console.log("主线程1")
awaitDemo();
console.log("主线程2")
//主线程1
//normalFunc
//主线程2
//something, ~~
//enough sleep~
混用:
async function async1() {
console.log('async1 start')// 2 主线程async1()调用
await async2()
console.log('async1 end') // 6 主线程内同步代码执行完毕后接着执行await函数内后面的代码(至此主线程内同步代码都执行完毕)
}
async function async2() {
console.log('async2')// 3 主线程async1() => async2() await 会先执行完async2()内的代码
}
console.log('script start')// 1 主线程同步代码
setTimeout(function() {
console.log('setTimeout') // 8 setTimeout放入宏队列中下次轮询执行
}, 0)
async1();
new Promise( function( resolve ) {
console.log('promise1') // 4 promise内的同步代码会在主线程内先执行
resolve();
} ).then( function() {
console.log('promise2') // 7 promise回调会放入微队列中,主线程代码执行完毕后执行
} )
console.log('script end') // 5 主线程同步代码
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout