浏览器常驻的线程:
- js 引擎线程(解释和执行js 代码, JS内核-V8引擎 ,js引擎用来解释执行js代码 )
- GUI 线程(绘制用户界面, 与js 主线程是互斥的);
- http 网络请求线程(处理用户的get, post 等请求等, 返回结果后讲回调函数推入到任务队列);
- 定时器触发线程(setTimeout, setInterval 等待时间结束后把执行函数推入到任务队列中);
- 浏览器事件处理线程(将click, mouse 等交互事件发生后将这些事件放入到事件队列中);
Promise是什么,Promise是为了解决怎么样的问题,Promise最终的解决方案是什么
可直接进行迭代的数据类型: Array,arguments,NodeList, Map,Set,TypeArray,String
首先这些对象之所以可以直接进行迭代的原因是因为对象上具有Symbol([Symbol.iterator])属性,这个属性对应着一个生成器函数,函数执行会返回一个迭代器,迭代器对象里面有个next方法,对这个next方法进行执行会返回一个迭代状态相关的对象{value:xxx, done: false/true}
var arr = [1, 2, 3, 4];
console.log(arr[Symbol.iterator]());
let iterator = arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
生成器的实现
function makeIterator() {
let _this = this,
index = 0;
return {
next() {
if(index < _this.length){
return {value: _this[index++], done: false}
}
return {value: undefined, done: true}
}
}
}
let arr = [1, 2, 3, 4]
Array.prototype.makeIterator = makeIterator;
let iter = arr.makeIterator();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
给对象配置Symbol.iterator接口
var obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]() {
let index = 0;
let map = new Map();
let propNames = Object.getOwnPropertyNames(this);
for(let i = 0; i < propNames.length; i ++){
map.set(propNames[i],this[propNames[i]]);
}
return {
next() {
var mapEntries = [...map.entries()];
if(index < map.size){
return {
value: mapEntries[index++][1],
done: false
}
}else{
return {value: undefined, done: true};
}
}
}
}
};
for(let value of obj){
console.log(value);
}
迭代和遍历有什么区别
迭代从目标源,逐个抽取的方式来提取数据
目标源:
1.有序的
2.连续的
生成器函数
生成器函数中的return是迭代器判断是否迭代完成的标志,如果没有手动return,最后就会返回 {value: undefined, done: true},如果手动return,比如return 1,则会返回{value: 1, done: true},当然第一次判断迭代完成之后你在next还是会返回{value: undefined, done: true}
function * test () {
return 1;
}
let iter = test();
console.log(iter); // test {<suspended>}
console.log(iter.next()); // {value: 1, done: true}
既然知道了生成器函数的写法,我们可以对之前部署的对象的Symbol.iterator接口进行改写。
var obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function * () {
let index = 0;
let map = new Map();
let propNames = Object.getOwnPropertyNames(this);
for(let i = 0; i < propNames.length; i ++){
map.set(propNames[i],this[propNames[i]]);
}
var mapEntries = [...map.entries()];
while(index < mapEntries.length){
yield mapEntries[index ++ ][1];
}
}
};
for(let value of obj){
console.log(value);
}
async/await函数 = 生成器函数 + 执行器函数
为什么要有Promise
因为过多的嵌套回调函数,会造成回调地狱的问题,代码难以维护
let fs = require('fs');
fs.readFile("./name.txt", 'utf-8', function (err, data) {
fs.readFile(data, 'utf-8', function (err, data) {
fs.readFile(data, 'utf-8',function (err, data) {
console.log(data);
});
})
})
异步?
首先js被设计为单线程的,这是为了防止DOM冲突的问题
事件轮询 异步任务会开启异步线程
异步的解决方案是事件轮询
事件轮询的核心是回调函数
回调函数 作为参数的函数就是回调函数,回调函数不一定是异步的
异步任务是否完成取决于promise对象的状态
promise三个状态:pendding(进行中),fullfilled(已经完成),rejected(失败)
promise写法
let fs = require('fs');
function readFile(pathName){
return new Promise(function (res, rej) {
fs.readFile(pathName, 'utf-8', function (err, data) {
if(err) {
rej(err);
}
res(data);
})
});
}
let p = readFile('./name.txt');
p.then(function (data) {
console.log(data);
}, function (err) {
console.log(err);
});
promise对象的状态一旦改变,就不会再改变,而且同个对象通过继续调用then方法,只能够在then方法的对应的回调函数执行时取到promise对象的状态值,如果回调函数不匹配当前promise对象的状态,则取不到值
//promise变为成功的状态之后,调用成功的回调函数会取得到值
let fs = require('fs');
function readFile(pathName){
return new Promise(function (res, rej) {
fs.readFile(pathName, 'utf-8', function (err, data) {
if(err) {
rej(err);
}
res(data);
})
});
}
let p = readFile('./name.txt');
p.then(function (data) {
console.log('第一次调用' + data);
p.then(function (data) {
console.log('第二次调用' + data);
p.then (function (data) {
console.log('第三次调用' + data);
});
})
}); //第一次调用./number.txt
//第二次调用./number.txt
//第三次调用./number.txt
//promise变为成功的状态之后,失败的回调函数不会执行,取不到值
let fs = require('fs');
function readFile(pathName){
return new Promise(function (res, rej) {
fs.readFile(pathName, 'utf-8', function (err, data) {
if(err) {
rej(err);
}
res(data);
})
});
}
let p = readFile('./name.txt');
p.then(function (data) {
console.log('第一次调用' + data);
p.then(function (data) {
}, function (err) {
console.log('第二次调用' + err);
p.then (function (data) {
console.log('第三次调用' + data);
});
})
});
//promise变为失败的状态之后,调用失败的回调函数会取得到值
let fs = require('fs');
function readFile(pathName){
return new Promise(function (res, rej) {
fs.readFile(pathName, 'utf-8', function (err, data) {
rej(data);
})
});
}
let p = readFile('./name.txt');
p.then(function (data) {
}, function (err) {
console.log('第一次调用 ' + err);
p.then(function (data) {
}, function (err) {
console.log("第二次调用 " + err);
p.then(function (data) {
}, function (err) {
console.log("第三次调用 " + err); //第一次调用 ./number.txt
//第二次调用 ./number.txt
//第三次调用 ./number.txt
});
});
});
promise相关方法:Promise.resolve/Promise.reject(静态方法),promise.then / promise.catch Promise.resolve或者Promise.reject会返回一个具有resolve或者reject状态的promise对象
//调用Promise.resolve,然后调用对象的.then方法
let p1 = Promise.resolve(1);
p1.then( function (data) {
console.log(data); //1
});
//调用Promise.reject,然后调用对象的.then方法
let p1 = Promise.reject(1);
p1.then( function (data) {
console.log(data);
}, function (err) {
console.log(err); //1
});
//第二种方法,调用对象的.catch方法获取失败状态的promise对象的数据
let p1 = Promise.reject(1);
p1.catch(function (err) {
console.log(err); //1
});
thenable对象,如果Promise.resolve()参数中传的不是原始值,而是一个对象,而且这个对象还有then方法,那么这个对象的then方法会被Promise.resolve()调用,并且then方法的两个参数会被注入promise改变状态相关的resolve/reject函数,如果调用的是Promise.reject的话,直接返回这个对象作为promise对象的状态对应值
//a是一个thenable对象
let a = {
then (resolve, reject) {
resolve(1);
}
}
//被当做参数传入Promise.resolve会被调用then方法,而且把改变promise对象的resolve和reject函数注入then方法的参数之中,形参接收之后执行就能够改变p1的状态
let p1 = Promise.resolve(a);
p1.then(function (data) {
console.log(data); // 1 这是成功的状态
});
//失败的状态
let a = {
then (resolve, reject) {
reject(1); //调用了reject来改变promise对象的状态
}
}
let p1 = Promise.resolve(a);
p1.catch(function (err) {
console.log(err);
});
//thenable对象失效的情况
let a = {
then (resolve, reject) {
reject(1);
}
}
let p1 = Promise.reject(a);
p1.catch(function (err) {
console.log(err); //只会返回原对象 $ node test
{ then: [Function: then] }
});
promise一道简单的题
Promise.resolve().then(function (data) {
console.log('promise1');
setTimeout( () =>{
console.log('setTimeout2');
},0);
});
setTimeout( function (){
console.log('setTimeout1');
Promise.resolve().then(function (data) {
console.log('promise2');
});
},0);
//promise1
//setTimeout1
//promise2
//setTimeout2
.then方法本身其实是同步的,.then方法会返回一个promise对象,如果promise对象还是pending状态时调用他的.then方法,会把回调函数先挂起,等到promise对象的状态改变时,回调函数会立马被推进微任务队列中,然后事件轮询机制会看微任务队列还有宏任务队列中的任务,优先执行微任务
let p1 = new Promise(function (res, rej) {
res(1);
});
let p2;
let p3 = p1.then( function (data) {
console.log(1);
p2 = new Promise(function (res, rej) {
setTimeout(function () {
console.log(3);
res(4);
});
setTimeout(function () {
console.log(5);
});
});
return p2;
}).then(function (data) {
console.log(data);
});
setTimeout(function () {
console.log(2);
},0);
// 1 2 3 4 5
promise的链式调用,promise.then仍然会返回一个promise对象,这个对象内部的value值取决于promise.then中的回调函数的返回值, 如果返回值不是一个promise对象,那就会隐式调用Promise.resolve() 给这个promise.then返回的promise对象设定一个值,如果回调函数中本来返回的是一个promise对象,那promise.then返回的promise对象的值取决于这一个promise对象的值。
let p1 = Promise.resolve( new Promise(function (res, rej) {
res(1);
})).then(function (data) {
console.log(data);
});
Promise.all
Promise可以用来返回一个promise对象,这个对象的value值是多个异步请求的结果组成的数组,而且这个结果是多个异步请求都拿到结果之后才会返回,Promise.all接收的也是数组,但是这个数组特殊,数组的成员是promise对象
let p1 = new Promise(function (res, rej) {
setTimeout( () => {
res(1000);
});
}, 1000);
let p2 = new Promise(function (res, rej) {
setTimeout(() => {
res(2000);
}, 2000);
});
let p3 = new Promise( (res, rej) => {
setTimeout( () => {
res(3000);
}, 3000);
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function (data) {
console.log(data); //[1000, 2000, 3000]
});
Promise.race
Promise.race返回的也是一个promise对象,Promise.race参数中的promise对象中哪个先变成pending,他的值就是Promise.race执行后返回的promise对象取到的值
let p1 = new Promise(function (res, rej) {
setTimeout( () => {
res(1000);
});
}, 1000);
let p2 = new Promise(function (res, rej) {
setTimeout(() => {
res(2000);
}, 2000);
});
let p3 = new Promise( (res, rej) => {
setTimeout( () => {
res(3000);
}, 3000);
});
let p4 = Promise.race([p1, p2, p3]);
p4.then(function (data) {
console.log(data); //1000
});
使用promise读取文件
function readFile (fileName) {
return new Promise(function (resolve,reject) {
fs.readFile(fileName, 'utf-8', function (err, data) {
resolve(data);
});
});
}
readFile('./name.txt')
.then(function (data) {
console.log(data);
return readFile(data) //将name.txt的内容传入,即number.txt作为路径
})
.then(function (data) {
console.log(data);
return readFile(data) //将number.txt的内容传入,即score.txt作为路径
})
.then(function (data) {
console.log(data); //将score.txt的值打印出来
})
async/await函数
//await是一个操作符 //等待一个Promise对象产出结果的操作手段 //功能是暂停async函数的执行,等待Promise处理后的结果 //假如Promise处理的结果是rejected,会抛出异常 async函数是通过一个隐式的Promise(pendding状态)