同步与异步
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>同步与异步</title>
</head>
<body>
<!-- 定数器 -->
<script>
/**
* (一): 同步与异步
* 1. 同步: 顺序执行, 优点: 静态预判结果可控, 缺点: 耗时任务阻塞执行
* 2. 异步: 乱序执行, 优点: 不会阻塞代码,体验好, 缺点: 顺序不可控
*
* 以银行排队办业务为例
* 1. 同步: 默认排队叫号, 依次办理
* 2. 异步: 耗时任务(如修改密码忘带身份证)则离开队列, 后面任务继续
* 3. 任务队列: 取了身份证回来了, 就待在"任务队列"中等待再次叫号
*
* 哪些是异步任务(耗时)?
* 1. 定时任务: setTimeout, setInterval
* 2. 事件监听: addEventListener
* 3. 网络请求: ajax, promise,fetch
* 4. 文件读写等涉及IO的操作
*
* -----------------------------------------------------------------
*
* (二) 进程与线程
* 1. 进程: 程序的运行状态, 执行实例
* 2. 一个cpu同一时刻只能执行一个进程,通过上下文切换实现多任务,除非多核
* 3. 线程: 进程中的某个任务,即一个进程,可以由多个线程完成
* 4. js的特征,决定了它只能是单线程,例如dom操作中, 增删元素就不可能同时进行
* 5. 单线程可确保js按用户要求的顺序执行,并确定业务逻辑正确,结果可控
* 6. 但是单线程,也决定了所有任务必须在一个执行栈中完成,导致耗时任务必然会阻塞整个线程
* 7. 解决文案: 任务队列与事件循环(事件轮询)
* 通信解释:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
*
* -----------------------------------------------------------------
*
* (三) 单线程,任务队列,事件循环之间的关系与协同
* 1. js所有任务都在主线程中"同步"执行
* 2. 异步任务以回调的形式声明,并离开主线程,交给多线程的浏览器去执行
* 3. 异步任务执行完毕,进入到"任务队列"中排队等待进入主线程执行
* 4. 主线程同步任务全部完成后, 通过"事件循环"查询"任务队列"中是否有等待的任务
* 5. 如果有,则该就绪任务进入主线程同步执行
* 6. 该任务完成后, 事件循环会再次取出下一个就绪的异步任务进入主线程
* 7. 以上过程不断重复, 直到主线程中的同步任务, 任务队列中的异步任务全部执行完毕
*/
// 定时器演示
// console.log(): 同步代码, 在函数栈/单线程中执行
console.log('100');
console.log('200');
console.log('300');
console.log('--------');
console.log('10');
setTimeout(function(){
console.log('20');
},5000);
setTimeout(() => {console.log('21'); },6000);
setTimeout('console.log(400)', 2000);
console.log('30');
// 异步任务优先级比 setTimeout高
window.onload = ( ) => console.log('等待');
</script>
</body>
</html>
效果
ajax-xhr
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ajax-xhr</title>
</head>
<body>
<button onclick="getUser1(this)">查询用户信息:XHR</button>
<button onclick="getUser2(this)">查询用户信息:fetch</button>
<script>
// AJAX : 局部更新,用户不需要离开当前页面就能看到新内容
// 1. 传统 XHR
/**
* 1. 创建对象: new XMLHttpRequest();
* 2. 响应类型: xhr.responseType = "json";
* 3. 配置参数: xhr.open("GET", url, true);
* 4. 请求回调: xhr.onload = () => console.log(xhr.response);
* 5. 失败回调: xhr.onerror = () => console.log("Error");
* 6. 发起请求: xhr.send(null);
*
* xhr 至少监听2个事件: load,error, 调用2个函数: open,send
* post请求,需要设置一下请求头与请求的数据,其它与get请求完全相同
*/
function getUser1 ( btn) {
// 1. 创建对象: new XMLHttpRequest();
const xhr = new XMLHttpRequest();
// * 2. 响应类型: xhr.responseType = "json";
xhr.responseType = "json"
// * 3. 配置参数: xhr.open("GET", url, true); 默认 是 true 可以不写
// let url = 'https://jsonplaceholder.typicode.com/users';
let url = 'https://jsonplaceholder.typicode.com/users?id=1';
// 不传 get 参数默认是所有用户信息 , // 如果有get参数,用户id,用ul列表显示
xhr.open("GET", url, true);
// * 4. 请求回调: xhr.onload = () => console.log(xhr.response);
xhr.onload = () =>
{
console.log(xhr.response);
render(xhr.response, btn);
}
// * 5. 失败回调: xhr.onerror = () => console.log("Error");
xhr.onerror = () => console.log("Error");
// * 6. 发起请求: xhr.send(null);
xhr.send(null);
}
</script>
<script>
//2、 fetch 链式操作 操作都是异步的,通过then 使顺序可控. then (里面是函数)
/**
* fetch(url)
* .then(res)
* .then(...)
* .catch(err)
*/
function getUser2 ( btn ) {
let url = 'https://jsonplaceholder.typicode.com/users?id=2';
fetch( url)
.then (function (response){
return response.json();
} )
.then (function(json){
// 控制台
console.log(json);
// 页面渲染到页面
render(json,btn)
} );
/**
* xhr 与 fetch?
* 1. xhr: 传统ajax
* 2. fetch: 现代异步请求, 推荐,基于Promise对象
*/
}
</script>
<script src="../0801/0801/js/function.js"></script>
</body>
</html>
效果
fetch-api 、async、await
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>fetch-api 、async、await</title>
</head>
<body>
<!-- fetch-api 是浏览器原生实现的异步技术 可直接用 -->
<button onclick="getUser(this)">查询用户信息: Fetch</button>
<script>
// axios : 基于 异步 xhr 、fetch
// fetch :基于 promise ,返回 promise 对象
// console.log(fetch());
// fetch('https://jsonplaceholder.typicode.com/todos/1')
// .then(response => response.json())
// .then(json => {
// console.log(json)
// });
// async 当前是个异步函数
async function getUser( btn){
let url = 'https://jsonplaceholder.typicode.com/todos/1';
// 异步耗时操作,需要等待结果才能进入一下步
const response = await fetch(url);
// 获取到 结果之后,再转为json
const result = await response.json()
console.log(result);
render(result,btn);
}
</script>
<script src="../0801/0801/js/function.js"></script>
<script>
// fetch api : 浏览器原生实现的异步技术
// axios: 基于 xhr / fetch
// fetch: 基于Promise, 返回 Promise对象
// console.log(fetch());
// fetch('https://jsonplaceholder.typicode.com/todos/2')
// .then(response => response.json())
// .then(json => console.log(json));
// fetch('https://jsonplaceholder.typicode.com/users')
// .then(response => response.json())
// .then(json => console.log(json));
// 下面我们请求自己的数据接口
// let url = 'http://website.io/users.php';
// fetch(url)
// .then(response => response.json())
// .then(json => console.log(json));
// 报 CORS 跨域请求错误
// 同源策略: 仅允许"协议相同,域名相同,端口相同",否则就是跨域请求,这是禁止的
// function getUser(btn) {
// let url = 'http://website.io/users.php?id=1';
// fetch(url)
// .then(response => response.json())
// .then(json => {
// console.log(json);
// // 将数组渲染到页面中
// render(json, btn);
// });
// }
// ECMA2017中, 有async,await,用来简化异步回调方法
// async: 当前是一个异步函数
</script>
</body>
</html>
效果
模块的导入与导出
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模块成员导出与导入</title>
</head>
<body>
<!-- 默认script在浏览器环境下不支持模块,需要指定type -->
<script type="module">
// js中, 所有代码共用一个全局作用域: window
// 导入模块
import { username1, hello } from './zuoyemodules/m1.js';
console.log(hello());
console.log(username1);
console.log(hello(username1));
console.log('==============');
import{ username2, hello2 }from './zuoyemodules/m1.js';
console.log(hello2());
console.log(username2);
console.log(hello(username2));
console.log('==============');
import {myname,getName} from './zuoyemodules/m1.js';
console.log(getName());
console.log(myname);
console.log(getName(myname));
console.log('==============');
// 当前模块中不允许有 重名的成员
import { myname4 as name , getName4 as getUser } from './zuoyemodules/m1.js';
let myname4 = '小龙'
function getName4 (name) {
return 'hell' +name;
}
console.log(name);
console.log(getUser(name));
console.log('==============');
// 导入模块的默认成员 不要用对象字面量,用标识符
// 只要不用对象字面量接收模块成员,就是默认导出
// 自己命名 User
import User from './zuoyemodules/m1.js';
console.log(typeof User);
const user = new User('小猫')
console.log(user.username5);
console.log(user.geUsername5(user.username5));
console.log('==============');
// 只要不用对象字面量接收模块成员,就是默认导出
// 混合导入
// 接收混合导入成员,默认成员命名,必须要放到 非默认的前面
// import useremail , { username6, hello6} from './zuoyemodules/m2.js';
// console.log(useremail);
// console.log(username6);
// console.log(hello6(username6));
</script>
</body>
</html>
JS
// js 模块知识
// 模块就是一个js文档
// 模块有自己独立的作用域(全局、函数、块)
// 模块内成员,默认全部私有。只有导出后才能呗外部使用
// 1、逐个导出
// export let username1 = "小猪" ;
// export function hello (username1){
// return 'hello, ${username1}';
// // return ' ${username1}';
// }
export let username1 = '猪老师';
export function hello(username1) {
// 注意反引号
return `Hello, ${username1}`;
}
// 2、批量导出
// 两步走
// 2.1、声明
let username2 = '小狗';
function hello2 (username2 ){
// 注意反引号
return `hello,${username3}`;
}
// 2.2批量导出
export {username2,hello2};
// 3 别名导出
// 3.1声明
let username3 = '小马';
function hello3 (username3){
return `Hello, ${username3}`;
}
// 3.2 别名导出
export {username3 as myname ,hello3 as getName};
// 4 别名导出
// 4.1声明
let username4 = '小马';
function hello4 (username4){
// 注意反引号
return `hello,${username4}`;
}
// 4.2 别名导出
export {username4 as myname4 ,hello4 as getName4};
//5、 默认导入
// 5.1、
export default class {
constructor (username5) {
this.username5 =username5;
}
geUsername5 (){
return `hell0 , ${this.username5}`;
}
}
效果
混合导出与命名空间
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>混合导出与命名空间</title>
</head>
<body>
<script type="module">
import useremail , { username6, hello6} from './zuoyemodules/m2.js';
console.log(useremail);
console.log(username6);
console.log(hello6(username6));
console.log('=========');
// 导入的成员过多时,使用 {。。。。}会很长
// 可以将所有导入的成员都挂载到 一个对象上
// 此时导入的模块成员,自动成为该对象的属性
// 这个对象就是命名空间
import * as user from './zuoyemodules/m2.js';
console.log(user);
console.log(user.username6);
console.log(user.hello6(username6));
console.log(user.default);
console.log(user.hello6(user.username6));
</script>
</body>
</html>
js
//6、 混合导出 默认成员与非默认成员的导出
// 6.1、
let username6 = '小妞';
function hello6 (username6) {
return `hel ,${username6}`;
}
let email6= '1234@qq.com';
// // 私有成员不对外
let sex = 'male';
// // 将邮箱 email6作为默认导出
export {username6 ,hello6 , email6 as default};
效果