前言
通过阅读这本书写下的一些笔记
《JavaScript高级程序设计》
第11章——期约与异步函数
- 11.2 期约(promise):是对 尚不存在结果 的一个替身。
/**
* 期约与异步函数
* 什么是Promise?
* (1)从语法上来说:Promise是一个构造函数
* (2)从功能上来说:Promise对象用来封装一个异步操作并获取其结果。
* Promise基本远行流程
* (1)创建一个新的Promise 对象
* (2) 执行异步操作任务
* (3)异步任务成功则返回resolve(),失败则返回reject()
* (4)resolved状态通过then()回调onResolved();rejected状态通过then()/catch()回调onReject()
* (5)最后形成一个新的Promise对象
*/
//失败处理
function double(value,success,failure){
setTimeout(() => {
try{
if(typeof value !== 'number'){
throw 'Must provide number as firdt argument';
}
success(2 * value);
}catch(e){
failure(e);
}
},1000);
}
const successCallback = (x) => console.log('Success:${x}');
const failureCallback = (e) => console.log('Failure:${e}');
double(3,successCallback,factorialCallack);
double('b',successCallback,factorialCallack);
//嵌套异步回调
function double(value,success,failure){
setTimeout(() => {
try{
if(typeof value !== 'number'){
throw 'Must provide number as firdt argument';
}
success(2 * value);
}catch(e){
failure(e);
}
},1000)
}
const successCallback = (x) => {
double(x,(y) => console.log('Success:${y}'));
};
const failureCallback = (e) => console.log('Failure:${e}');
double(3,successCallback,failureCallback);
Promise 对象状态改变的方式:
//1.声明一个Promise对象的状态
let p = new Promise((resolve,reject) => {
//resolve 函数
resolve('OK');//pending =>fulfilled(resolve)
//reject 函数
reject('Error');//pending => rejected
//抛出错误
throw '出问题了';
});
console.log();
//Promise指定多个成功/失败回调函数,都会调用嘛?
//当Promise改变为对应状态时,都会被调用
let p = new Promise((resolve,reject) => {
resolve('OK');
});
//指定回调
p.then(value => {
console.log(value);
});
//指定回调
p.then(value => {
alert(value);
});
三种状态:待定(pending)、兑现(resovle)、拒绝(reject)
/**
* promise 期约是对尚不存在结果的一个替身
* 三种状态:待定(pending)、兑现(fulfilled,可以叫解决(resolve))、拒绝(rejected),三种状态不可逆
* 待定(pending):期约的最初始状态。
* 兑现(fulfilled):期约落定(settled)为代表成功状态
* 拒绝(rejected):期约落定(settled)为代表失败状态
* 用途:抽象的表示一个异步操作;状态代表期约是否完成。
*/
let p = new Promise(() => {});
setTimeout(console.log,0,p);
let p1 = new Promise((resolve,reject) => resolve());
setTimeout(console.log, 0 ,p1)//Promise {<fulfilled>: undefined}
let p2 = new Promise((resolve,reject) => reject());
setTimeout(console.log, 0 ,p2)//Promise {<rejected>: undefined}
Promise.prototype.then()为Promise实例添加状态改变时的回调函数。
//then方法返回的是一个新的Promise实例。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved:",comments),
err => console.log("rejected:",err)
);
Promise.prototype.catch() 发生错误时的回调函数。
const somrAsyncThing = function(){
return new Promise(function(resolve,reject){
resolve(x + 2);//会报错,因为x没有声明
});
};
somrAsyncThing().catch(function(error){
console.log('error',error);
}).then(function(){
console.log('error');
});
Promise.prototype.finally() 不管Promise对象最后状态如何,都会执行的操作。
let p1 = Promise.resolve();
let p2 = Promise.reject();
let onFinally = function(){
setTimeout(console.log, 0, 'Finally!')
}
p1.finally(onFinally);//Finally
p2.finally(onFinally);//Finally
Promise.all() 接收一个可迭代对象,返回一个新期约,在一组期约全部解决之后再解决。
const p1 = new Promise((resolve,reject) => {
resolve("hello");
}).then(result => result);
const p2 = new Promise((resolve,reject) => {
throw new Error('error');
}).then(result => result);
Promise.all([p1,p2])
.then(result => console.log(result))
.catch(e => console.log(e));
Promise.race() 将多个Promise实例,包装成一个新的Promise实例。
const p = Promise.race([p1,p2,p3]);//只要有一个实例率先改变状态,P的转态就会发生改变
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function(resolve,reject){
setTimeout(() => reject(new Error('request timeout')),5000)
})
]);
p.then(console.log).catch(console.error);
- 11.3 异步函数:旨在解决利用异步结构 组织代码的问题
async关键字用于声明异步函数,它是Generator 函数的语法糖。
async function foo(){}
let bar = async function(){};
let baz = async () => {};
class Qux{
async qux(){}
}
let p = new Promise((result,reject) => setTimeout(result,1000,3));
p.then((x) => console.log(x));//3
await关键字用于暂停步函数代码的执行,等待期约解决。
async function foo(){
let p = new Promise((resolve,reject) => setTimeout(resolve,1000,3));
console.log(await p);
}
foo();//3
//停止和恢复执行
async function foo(){
console.log(2);
await null;
console.log(4);
}
console.log(1);
foo();
console.log(3);
//1
//2,打印完2后,由于遇到arait关键字,null向消息队列添加一个任务,退出foo()
//3.打印完3,再次回到foo()中恢复执行。
//4
async function foo(){
console.log(2);
console.log(await Promise.resolve(8));
console.log(9);
}
async function bar(){
console.log(4);
console.log(await 6);
console.log(7);
}
console.log(1);
foo();
console.log(3);
bar();
console.log(5);
手写Promise :
// 参见的内置错误
// 1).ReferenceError:引用的变量不存在
console.log(a); //Uncaught ReferenceError: a is not defined
// 2).TypeError:数据类型不正确
b = {}
b.xxx()//VM274:2 Uncaught TypeError: b.xxx is not a function
//3).RangeError:数据值不在其所允许的范围内
function fn(){
fn()
}
fn()//ncaught RangeError: Maximum call stack size exceeded
//4).SyntaxError:语法错误
const c = "''"
//创建一个Promise对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const time = Date.now();
if(time % 2 == 0){
resolve('成功的数据,time='+time);
}else{
reject('失败的数据,time='+time);
}
}, 1000);
})
p.then(
value => {
console.log('成功的回调'+value);
},
reason => {
console.log('失败的回调,time='+reason);
}
)
//Promise对象用来封装一个异步操作并返回其结果
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的数据')
reject('失败的数据')//这一部分将不起作用,promise每次调用只返回一种结果
},1000)
})
//Promise.then()
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的数据')
},1000)
}).then(
value => {
console.log('onResolved()1',value)//onResolved()1 成功的数据
}
).catch(
reason => {
console.log('onReject()1',reason)
}
)
/**
* 语法糖:用起来很甜,方便的传值方式
*/
//Promise.resolve()
//产生一个成功值为1的promise的值
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
const p2 = Promise.resolve(2);//语法糖
const p3 = Promise.reject(3);//语法糖
p1.then(value => {console.log(value)});
p2.then(value => {console.log(value)});
p3.catch(reason => {console.log(reason)});
//Promsie.all()都为resolve才算成功,否则返回reject
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
const p2 = Promise.resolve(2);//语法糖
const p3 = Promise.reject(3);//语法糖
const pAll = Promise.all([p1,p2,p3])//其中3是一个失败的结果
pAll.then(
values => {
console.log('all onReasoned()',values);
},
reason => {
console.log('all onRejected()',reason);//all onRejected() 3
}
)
//Promise.race()只要有一个resolve/reject就返回其结果
//如果在异步情况下,p1,p2,p3谁先到就去谁的结果
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
const pRace = Promise.race([p1,p2,p3])
pRace.then(
value => {
console.log('race onResolve()',value)
},
reason => {
console.log('race onRejected()',reason)
}
)
/**
* Promise.then()返回的promise的结果由什么所决定?
* (1)简单表达:由then() 指定的回调函数 执行的结果 决定
* (2)详细表达:
* ①如果抛出异常,新promise变为reject,reason为抛出的异常。
* ②如果返回的是非promise的值,新promise变为resolved,value为返回的值
* ③如果返回的是另一个新的promise,次promise的结果就会编程新promise的结果
*/
new Promise((resolve, reject) => {
resolve(1);//onResolved1() 1 onResolved2() undefined
// reject(1);//onRejected1() 1 onResolved2() undefined
}).then(
value => {
console.log('onResolved1()',value);
return 2
// return Promise.resolve(3)
// return Promise.reject(4)
// throw 5
},
reason => {
console.log('onRejected1()',reason);
}
).then(
value => {
console.log('onResolved2()',value);
},
reason => {
console.log('onRejected2()',reason);
}
)
/**
* Promise如何串联多个操作任务?
* (1)promise的then()返回的一个新的promise,可以开成then()的链式调用。
* (2)通过then的链式调用串连多个同步/异步任务
*/
new Promise ((resolve, reject) => {
setTimeout(() => {
console.log("执行任务1(异步)");
resolve(1)
},1000);
}).then(
value =>{
console.log("执行任务2的结果:",value);
console.log("执行任务2(同步)");
return 2;
}
).then(
value => {
console.log("执行任务3的结果:",value)
}
)
/**
* promise异常穿透?
* (1)当使用promise的then链式调用时,可以在最后 指定失败的回调。
* (2)前面任何操作做出了异常,都会传到最后失败的回调处理。
* 中断promise链?
* (1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
* (2)办法:在回调函数中返回一个pending状态的promise对象
*/
new Promise ((resolve, reject) => {
resolve(1)
}).then(
value =>{
console.log("onRsolved1()",value);
}
).then(
value => {
console.log("onRsolved2()",value)
}
).then(
value => {
console.log("onRsolved3()",value)
}
).catch(
reason => {
console.log('onReasoned4()',reason)
}
)
宏任务跟微任务:
/**
* 1.JS中用来存储执行回调函数的队列包含2个不同特定的队列
* 2.宏队列:用来保存待执行的宏任务(回调),比如:dom事件回调、Ajax回调、定时器setTime回调
* 3.微嘟列:用来保存待执行的微任务(回调),比如:promise回调、MutaionOberver回调
* 4.JS执行时会区别这2个队列、
* (1).JS引擎首先必须先执行所有的初始化同步任务代码。
* (2).每次准备取出第一个宏任务执行前,都要讲所有的微任务一个个取出来执行。
*/
setTimeout(() => {//宏任务 3
console.log("callback1()")
Promise.resolve(3).then(//微任务 4
value => {
console.log("onResolve3()",value)
}
)
},0)
setTimeout(() => {//宏任务 5
console.log("callback2()")
},0)
Promise.resolve(1).then(//微任务 1
value => {
console.log("onResolve1()",value)
}
)
Promise.resolve(2).then(//微任务 2
value => {
console.log("onResolve2()",value)
}
)
//onResolve1() 1
//onResolve2() 2
//callback()
//onResolve3() 3
//callback()
setTimeout(() => {
console.log(1)
},0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
//2 5 3 4 1
async 函数和await 函数
/**
* 1.async 函数
* 函数的返回值为promise对象。
* promise对象的结果由async函数执行的返回值决定。
* 2.await 表达式
* await 右侧的表达式一般为promise对象,但也可以是其他的值,
* 如果表达式是promsie对象,await返回的是promise成功的值,
* 如果表达式是其他值,直接将此值作为await的返回值。
*
*/
async function fn1(){
return 1
// throw 2
// return Promise.reject(3)
}
const result = fn1()
result.then(
value => {
console.log('onResolved',value);//onResolved 1
},reason => {
console.log('onRejected',reason)
}
)
function fn2(){
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(6)
},1000)
})
}
function fn4(){
return 6;
}
async function fn3(){
const vlaue = await fn2();
console.log('value',value)
}
fn3()
第12章——BOM
- 12.1 Windwos对象
BOM 的核心是windows对象,windows对象有两个身份,另一个是ECMAScript中的Global对象,另一个是浏览器窗口的JavaScript接口。
BOM和DOM的区别:
① DOM:文档对象模型,描述了处理网页内容的方法和接口(windows.document)。
② BOM:浏览器对象模型,描述了与浏览器进行交互的方法和接口(navigater、history、screen、location、windows)。
第13章——客户端检测
- 能力检测:检测浏览器是否含有某种特性
- 用户代理检测:通过用户代理字符串确定浏览器。
第14章——DOM
DOM表示由多层节点构成的文档,DOM树。
Element Traversal API 五个属性:
childElementCount,返回元素数量(不包含文本节点和注释)。
firstElementChild,指向第一个Element类型的子元素。
lastElementChild,指向最后一个Element类型的子元素。
previousElementSibling,指向前一个Element类型的同胞元素。
nextElementSibling,指向后一个Element类型的同胞元素。
第15章——DOM拓展
-
15.1 Selectors API
-
querySelector()返回匹配该模式的第一个后代元素,如果没有匹配项则返回结果null。
/** * DOM编程 */ var script = document.createElement("script"); var code = "function sayHi(){alert('h1');}"; try{ script.appendChild(document.createTextNode("code")); }catch(ex){ script.text = "code"; } document.body.appendChild(script);//<script>dode</script> //querySelector()接收CSS选择符参数,返回匹配该模式的第一个后代元素。 let myDiv = document.querySelector("#myDiv"); //querySelect()接收CSS选择符参数,返回所有匹配的节点。 let ems = document.querySelectorAll("p strong");//取得所有是<p>元素子元素的<strong>元素 //DOM对象转Jquery对象 var box = document.getElementsByClassName('.box'); var jq = $(box); //获取所有div的第0个位置的div var domeObject = $('div')[0]; //Jquery对象转换成DOM对象 myvideo.play();//直接调用
第17章——事件
- 17.1 事件流:页面接收事件的顺序。
- 事件传播的三个阶段:
- ①事件捕获阶段:事件是从Document节点自上而下向目标节点传播。
- ②目标阶段:达到事件对象的事件目标,找到目标节点后完成后停止。
- ③事件冒泡阶段:事件再从目标节点自下而上向Document节点传播。
第20章——Streams API
-
20.2 跨上下文消息:一种执行在不同上下文间传递消息的能力。核心是postMessage()方法。
-
postMessage()方法接收三个参数:消息(data)、文档源(origin)、文档中的windows对象代理(souce)。
-
let iframeWindow = document.getElementById("myframe").contentWindow; iframeWindow.postMessage("A secret","http://www.xxxx.com");//指定源www.xxx.com,x`向内嵌窗格发送一条消息
-
Streams API
-
可读流:通过公共接口读取数据块的流,由消费者进行处理,使用getReader()方法获取流的锁
async function* ints(){ //每1000毫秒生产一个递增的整数 for(let i = 0;i<5;++i){ yieled await new Promise((resovle) => setTimeout(resovle,1000,i)); } } const resdableStream = new ReadableStream({ async start(controller){ for await (let chuck of ints()){ controller.enqueue(chunk); } controller.close } })
-
可写流:通过公共接口写入数据块的流,生产者将数据写入流。
-
转换流:包含可读流和可写流,可根据需要检查和修改流内容。
-
20.11 Web组件
-
一套用于增强DOM行为的工具,包括影子DOM、自定义元素和HTML模板。
-
影子DOM通过attachShadow()方法创建并添加给有效HTML元素。
/**
* 读取拖放元素
*/
let droptarget =document.getElementById("droptarget");
function handleEvent(event){
let info = "",
output = document.getElementById("output");
Files, i,len;
event.preventDefault();
if(event.type == 'drop'){
file = event.dataTransfer.failes;
i = 0;
len = failes.length;
while(i<len){
info += `${files[i].name} (${files[i].type},${files[i].size} bytes)<br>`;
i++;
}
output.innerHTML = info;
}
}
droptarget.addEventListener("dragenter",handleEvent);
droptarget.addEventListener("dragover",handleEvent);
droptarget.addEventListener("drop",handleEvent);
//链式调用
function person(){
}
person.prototype.getName=function(name){
this.name = name;
return this;
}
person.prototype.getAge=function(age){
this.age = age;
return this;
}
const a = new person().getName('kuishou').getAge('21')
console.log(a);
第23章——解析与序列化
- 23.2 JSON对象
- 序列化:stringify()方法,第一个参数是过滤器,可以是数组或函数;第二个参数用于缩进结果JSON字符串的选项。
- 解析:parse()方法又叫复活函数,包含两个参数,属性名(key)和属性值(value)。可以接收一个额外的参数,这个函数会正对每个键/值对都调用一次。
第24章——网络请求与远程资源
- GET请求:用于向服务器查询某些信息。
- POSE请求:哟用于向服务器发送应该保存的信息。
- Fetch API :浏览器会向给定的URL发送请求,读取响应、处理状态码
- Web Socket(套接字):通过一个长时连接实现与服务器全双工、双向的通信。在JavaScript创建Web Socket的时候,一个HTTP请求会发送到服务器以初始化连接,服务器响应后,连接使用的Upgrade头部从HTTP切换到Web Socket协议,使用该协议的专有服务器。
第26章——模块
- 本质上是键/值实体,
- ES6模块默认在严格模式下执行,不共享全局命名空间。
第27章——工作者线程
-
JavaScript是单线程的,为了为了解决并发问题,JavaScript提出了工作者线程的三种类型
-
专用工作者线程:让脚本单独创建一个JavaScript线程,以执行委托的任务。
-
共享工作者线程:创建到的线程可以别多个不同的上下文使用,包括不同的页面。
-
服务工作者线程:拦截、重定向和修改页面发出的请求,充当王阔请求仲裁者的角色。
-
充当王阔请求仲裁者的角色。