发送网络请求
| 标题 | 内容 | 备注 | 特点 |
|---|---|---|---|
| AJAX | 用 JS 发请求和收响应 是一个技术统称,概念模型 特征是让页面实现局部刷新 | 浏览器提供XMLHttpRequest构造函数,可构造出xhr对象,JS 通过xhr实现部分刷新页面 | 存在跨域问题 若请求内部还有请求嵌套,就会有回调地狱问题 |
| Promise | 对异步操作的封装 | 可通过独立的接口添加在异步操作执行成功、失败时执行的方法 | 不可以取消请求 |
| Fetch API | 由Fetch标准定义,提供了一个获取资源的接口 Fetch的核心是对 HTTP 接口的抽象 | 使用.then链式调用 处理结果不使用回调函数 而用 Promise 比XMLHttpRequest的实现更简洁 fetch 可自定义是否携带Cookie | 不支持JSONP |
| async / await | 写异步代码的新方式 优于回调函数和Promise | 不需要写.then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量 | |
| axios | 基于promise封装的网络请求库 | 提供两个http请求适配器XHR和HTTP: XHR的核心是浏览器端的XMLHttpRequest对象 HTTP的核心是node的http.request方法 | 用CancelToken取消请求 |
AJAX
AJAX 直译为异步(Async) JS 和 XML ,是一种技术总结,是浏览器上的功能:
浏览器提供一套用于实现网络编程的 API ,可通过JS调用,从而实现用 JS 发请求和收响应。
异步的从服务器轻量级的获取新数据,在不重新加载整个页面的情况下,刷新页面。
JS 发网络请求到成功得到响应 这个过程的持续时间:几百毫秒至1-2s之间。
缺点
- 没有浏览历史,不能回退
- 存在跨域问题(用同源策略解决)
- SEO 搜索引擎优化不友好
应用场景
- 百度搜索关键字,显示的联想列表:
- 京东左侧栏,商品分类,浮动显示内容:
核心
浏览器可以发请求,收响应,是因为浏览器在window上加了一个XMLHttpRequest全局函数,用它可以构造出一个xhr对象,JS 通过操控xhr实现部分刷新页面。
xhr 的属性和方法 | 内容 |
|---|---|
send方法 | send(请求体) |
open方法 | open(请求方法, URL, 是否异步请求) |
readystate属性 | 用来对应服务器状态码 记录请求响应时候处于哪个过程 readystate属性值的变化会触发readystatechange事件 |
readyState的值的变化,就是一个请求的生命周期:
0 表示未调用open()方法
1 表示调用了open()方法,但未调用send()方法
2 表示已调用send()方法,还没收到响应
3 表示开始下载,已经接收到部分数据
4 表示已经接收到全部数据,可以把响应的内容显示在页面了
用 AJAX 加载 CSS
以前是用<link>标签加载 CSS,也可以用 AJAX 加载 CSS:
// index.html
<!DOCTYPE html>
<html>
<head>
<title>ajax</title>
</head>
<body>
<h1>AJAX demo 2</h1>
<p>
<button id="getCSS">请求 CSS</button>
</p>
<script src="/main.js"></script>
</body>
</html>
// main.js
getCSS.onclick = () => {
const request = new XMLHttpRequest();
request.open('GET','/style.css');
// `onload`比较局限,后来替换为`onreadystatechange`事件
request.onload = () => {
// 创建 style 标签
const style = document.createElement('style')
// 填写 style 内容
style.innerHTML = request.response
// 插到 head 里面
document.head.appendChild(style)
};
request.onerror = () => {
console.log('fail')
}
request.send()
}
用 AJAX 加载 JS
以前是用<script src="2.js"></script>标签加载 JS,也可以用 AJAX 加载 JS:
console.log('我是2.js')
// index.html
<!DOCTYPE html>
<html>
<head>
<title>ajax</title>
</head>
<body>
<h1>AJAX demo 2</h1>
<p>
<button id="getCSS">请求 CSS</button>
<button id="getJS">请求 JS</button>
</p>
<script src="/main.js"></script>
</body>
</html>
// main.js
getJS.onclick = () => {
const request = new XMLHttpRequest();
request.open('GET','/2.js');
// `onload`比较局限,后来替换为`onreadystatechange`事件
request.onload = () => {
// 创建 script 标签
const script = document.createElement('script')
// 填写 script 内容
script.innerHTML = request.response
// 插到 head 里面
document.head.appendChild(script)
};
request.onerror = () => {
console.log('fail')
}
request.send()
}
用 AJAX 加载 HTML
以前不会加载 HTML,
// 3.html
<div style="background:red; width:300px height:300px;">
动态内容
<div>
// index.html
<!DOCTYPE html>
<html>
<head>
<title>ajax</title>
</head>
<body>
<h1>AJAX demo 2</h1>
<p>
<button id="getCSS">请求 CSS</button>
<button id="getJS">请求 JS</button>
<button id="getHTML">请求 HTML</button>
</p>
<script src="/main.js"></script>
</body>
</html>
// main.js
getHTML.onclick = () => {
const request = new XMLHttpRequest();
request.open('GET','/3.html');
request.onload = () => {
// 创建 div 标签
const div = document.createElement('div')
// 填写 div 内容
div.innerHTML = request.response
// 插到 body 里面
document.body.appendChild(div)
};
request.onerror = () => {
console.log('fail')
}
request.send()
}
替换onload为onreadystatechange
// main.js
getCSS.onclick = () => {
const request = new XMLHttpRequest();
request.open('GET','/style.css');
request.onreadystatechange = () => {
// 下载完成,但不知道是成功 2xx 还是失败 4xx 5xx
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
const style = document.createElement('style')
// 填写 style 内容
style.innerHTML = request.response
// 插到 head 里面
document.head.appendChild(style)
}else{
alert('加载 CSS 失败')
}
}
};
request.send()
}
小结
// 发送请求的流程:
// 1. 创建一个请求代理对象 xhr
let xhr = new XMLHttpRequest();
// 2. 通过代理对象建立与服务端的连接
xhr.open('GET', 'http://xxx', 是否异步请求)
// 3. 基于连接发送请求
xhr.send()
// 接收响应的流程:
// 4. 等待服务端的响应 目前没有这种等待的说法
// 5. 接收到服务端的响应结果 响应报文中的响应体
xhr.onreadystatechange = function(){
// 请求状态发生变化时触发
}
- 由于 JS单线程,AJAX 并没有设计一个阻塞的方法,接收响应的方式是通过事件触发方式
onreadystatechange并不是专门设计的响应事件,只要是请求状态变了就触发xhr.responseText为获取响应报文的响应体
用 AJAX 加载 JSON
JSON 标记语言
用来展示数据,类似 HTML、Markdown;作者是道格拉斯;
支持的数据类型有:string(只支持双引号)、number、bool、null(没有undefined)、object、array
不支持的数据类型:函数和变量(不支持引用)
类型转换:
- JSON.parse 把符合JSON语法的字符串转换成 JS 对应类型的数据
- JSON.stringify 是 JSON.parse 的逆运算
实例
// 5.json
{
"name":"frank",
"age":"18",
"xxx":null
}
// index.html
<!DOCTYPE html>
<html>
<head>
<title>ajax</title>
</head>
<body>
<h1>AJAX Hello <span id="myName"></span></h1>
<p>
<button id="getJSON">请求 JSON</button>
</p>
<script src="/main.js"></script>
</body>
</html>
// main.js
getJSON.onclick = () => {
const request = new XMLHttpRequest();
request.open('GET','/5.json');
request.onreadystatechange = () => {
// 下载完成,但不知道是成功 2xx 还是失败 4xx 5xx
if(request.readyState === 4){
if(request.status >= 200 && request.status < 300){
const object = JSON.parse(request.response)
myName.textContent = object.name
}
}
};
request.send()
}
这也是一种用户登录后,显示用户名的方法。
用 AJAX 加载 分页
// db/page1.json
[
{"id":1},
{"id":2},
{"id":3},
{"id":4},
{"id":5},
{"id":6},
{"id":7},
{"id":8},
{"id":9},
{"id":10}
]
(待更新)
Fetch
ES6新特性 (XHR的替代品)
Fetch本质上是一种标准,该标准定义了请求、响应和绑定的流程。 Fetch标准还定义了Fetch() API,其提供了一个获取资源的接口(包括跨域),它类似于 XMLHttpRequest ,Fetch 的核心在于对 HTTP 接口的抽象,包括 Request,Response,Headers,Body等。
fetch()方法
用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。
let wtf = fetch('https://dog.ceo/api/breeds/image/random');
console.log(wtf); // Promise{}
fetch(url, options).then(function(response){
// 处理 HTTP 响应
}, function(error){
// 处理 网络错误
})
fetch() 参数 | 内容 | 备注 |
|---|---|---|
| 第一个参数 | url | GET方法 |
| 第二个参数 (可选参数) | {method, body, header, cookie} | POST方法 |
HTTP GET方法
fetch返回一个Promise,Promise对象有三个属性:原型、状态和结果。可以用Promise的方法来操作服务器响应的内容。
| Promise对象 | 内容 |
|---|---|
| 原型 | catch()、then()方法、json方法 |
| 状态 | fulfilled 成功执行 |
| 结果 | body、headers、status、url属性 |
fetch('https://dog.ceo/api/breeds/image/random')
// 用 then 指明请求成功我们需要执行什么动作
// then 里面传入的函数用来操控服务器响应的内容
// Promise对象的原型中有 json 方法,用于把服务器拿回来的数据处理为JS能操作的数据
.then( response => console.log(response.json()) )
fetch就是一个基于Promise语法的函数,Promise.then以后会返回一个Promise,
fetch.then也返回一个Promise,可以利用Promise的链式来处理:
fetch('https://dog.ceo/api/breeds/image/random')
.then( response => console.log(response.json()) );
.then( data => console.log(data) );
// 输出结果为一个对象,这个对象的message属性里面有图片的url地址
实现每次点击按钮的时候,都会调用fetch函数:把图片地址添加到img标签的src属性里,把fetch内容放在事件监听函数内,并把最后获取到的对象的message属性赋值给图片的src属性。
<button>点击获取单身狗的照片</button>
<img>
<script>
const button = document.querySelector('button');
const img = document.querySelector('img');
button.addEventListener('click', ()=>{
fetch('https://dog.ceo/api/breeds/image/random')
.then( response => response.json() );
.then( data => img.src = data.message );
})
</script>
HTTP POST方法
<button>点击获取单身狗的照片</button>
<input type="text" placeholder="请输入单身狗姓名">
<script>
const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', ()=>{
fetch('https://jsonplaceholder.typicode.com/users',{
method:'POST',
body: JSON.stringify({name:input.value}),
header:{
'"Content-Type":"application/json'
},
})
.then( response => response.json() );
.then( data => console.log(data) );
});
</script>
异步与回调
异步任务需要在得到结果时通知 JS 来拿结果。怎么通知?让 JS 留一个函数地址给浏览器,等异步任务完成时浏览器调用该函数地址,同时把结果作为参数传给该函数,这个函数是写给浏览器调用的,所以是回调函数。
区别:异步任务需要用到回调函数来通知结果,但回调函数不一定只用在异步任务里,回调可以用到同步任务里,array.forEach(n => console.log(n))这是同步回调。
如何识别异步函数
异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如AddEventListener, setTimeout,AJAX 处理的方式都不同,这些异步操作是由浏览器内核的webcore来执行的:
webcore的3种API | 内容 | 备注 |
|---|---|---|
| DOM Binding | 处理DOM绑定事件 | onclick事件触发时,回调函数会立即被webcore添加到任务队列中 |
| Network | 处理Ajax请求 | 在网络请求返回时,才会将对应的回调函数添加到任务队列中 |
| timer | 对计时器进行延时处理 | 当时间到达的时候,才会将回调函数添加到任务队列中 |
如果一个函数的返回值处于以下三个东西内部,那么这个函数就是异步的:
- setTimeout
- AJAX(即 XMLHttpRequest)
- AddEventListener
异步举例
请求 JSON 时,request.send()之后,并不能直接得到response,这是因为 JS 发网络请求到成功得到响应的大概时间段是几百毫秒到2秒钟之间,就是必须等到readyState变为4后,浏览器回头(将来)调用request.onreadystatechange函数,才能得到request.response,这跟餐厅给你发送微信提醒的过程是类似的。
异步任务有两个结果
- 方法一:回调接受两个参数
fs.readFile('./1.txt', (error, data)=>{
if(error){console.log('失败'); return}
console.log(data.toString()) // 成功
})
- 方法二:用两个回调
ajax('get', '/1.json', data=>{}, error=>{})
// 前面函数是成功回调,后面函数是失败回调
ajax('get', '/1.json',{
success:()=>{}, fail:()=>{}
})
// 接受一个对象,对象有两个 key 表示成功和失败
Promise
定义
Promise是前端解决异步编程的统一方案(ES6规范),最大的缺点是不可以取消请求,axios可以用CancelToken取消请求。
异步编程主要有:
// fs文件操作
require('fs').readFile('./index.html', (err, data)=>{})
// ajax网络请求
$.get('/server', (data)=>{})
// 定时器
setTimeout(()=>{}, 1000);
为什么要用 Promise
-
支持链式调用,可解决回调地狱问题;
-
指定回调函数的方式更加灵活:启动异步任务 => 返回promise对象 => 给 promise 对象绑定回调函数(可在异步任务结束后指定)
Promise 的状态
状态是实例对象中的一个属性PromiseState,状态只能改变一次,由pending到resolved或rejected,无论变为成功或失败,都会有一个结果数据。
| 属性值 | 内容 |
|---|---|
| pending | 未决定的(默认值) |
| resolved / fullfilled | 成功 |
| rejected | 失败 |
// 改变 Promise 对象状态的方式
let p = new Promise((resolve, reject)=>{
// 1. resolve 函数 由 pending 改为 resolved(fulfilled)
resolve('ok');
// 2. reject 函数 由 pending 改为 rejected
reject('error');
// 3. 抛出错误
throw 'error';
})
Promise 对象的值
对象的值是实例对象中的另一个属性PromiseResult,保存着对象成功或失败的结果,以下两个函数可以修改PromiseResult属性的值:resolve和reject
Promise 的 API
- Promise 构造函数
Promise(excutor){}
// excutor函数为同步调用
excutor = (resolve, reject) => {}
- Promise.prototype.then 方法
Promise实例必须实现then这个方法,用于指定成功或失败的回调函数,返回一个新的 promise 对象。必须可以接收两个函数作为参数
(onResolved, onRejected) => {}
- Promise.prototype.catch 方法
Promise.all方法
只有所有promise都成功才成功,只要有一个失败了就直接失败
// promises : 包含 n 个 promise 的数组
(promises)=>{}
let p1 = new Promise((resolve, reject)=>{
resolve('OK');
})
let p2 = Promise.reject('Error');
let p3 = Promise.resolve('oh,Yeah');
const result = Promise.all([p1, p2, p3]);
console.log(result);
// promises : 包含 n 个 promise 的数组
(promises)=>{}
let p1 = new Promise((resolve, reject)=>{
resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('oh,Yeah');
const result = Promise.all([p1, p2, p3]);
console.log(result);
Promise.race方法
第一个完成的 promise 的结果状态就是最终的结果状态:
let p1 = new Promise((resolve, reject)=>{
resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('oh,Yeah');
const result = Promise.race([p1, p2, p3]);
console.log(result);
举个栗子 定时器:
// v1.0
<div class="container">
<h2>Promise</h2>
<button id="btn">点击抽奖</button>
</div>
function rand(m, n){
return Math.ceil(Math.random()*(n-m+1))+m-1;
}
// 点击按钮 2s后显示是否中奖
// 获取元素对象
const btn = document.querySelector('#btn');
// 绑定单击事件
btn.addEventListener('click', function(){
setTimeout(()=>{
let n = rand(1,100);
if(n <= 30){alert('恭喜中奖')}
else{alert('再接再厉')}
}, 2000)
})
// v2.0 Promise 形式实现
<div class="container">
<h2>Promise</h2>
<button id="btn">点击抽奖</button>
</div>
// 构造函数接收一个函数类型的参数, 此函数还有两个函数类型的形参
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
let n = rand(1,100);
if(n <= 30){
resolve(); // 将 p 的状态设置为成功
}else{
reject(); // 将 p 的状态设置为失败
}
}, 2000);
});
function rand(m, n){
return Math.ceil(Math.random()*(n-m+1))+m-1;
}
// 调用 then 方法 指定成功或失败时的回调
// 接收两个函数类型的形参
// 第一(二)个函数是 p 的状态成功(失败)时的回调
p.then(()=>{
alert('恭喜中奖')
}, ()=>{
alert('再接再厉')
})
举个栗子 AJAX 请求:
// v1.0 ajax实现
<div class="container">
<h2>Promise 封装 AJAX 操作</h2>
<button id="btn">点击发送 AJAX</button>
</div>
<script>
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(){
// 1. 创建对象
const xhr = XMLHttpRequest();
// 2. 初始化
xhr.open('GET', 'https://api.xx'); // 第2个参数是api接口地址
// 3. 发送请求
xhr.send();
// 4. 处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);
}else{
console.log(xhr.status);
}
}
}
});
</script>
// v2.0 promise
<div class="container">
<h2>Promise 封装 AJAX 操作</h2>
<button id="btn">点击发送 AJAX</button>
</div>
<script>
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(){
// 创建 Promise
const p = new Promise((resolve, reject)=>{
// 1. 创建对象
const xhr = XMLHttpRequest();
// 2. 初始化
xhr.open('GET', 'https://api.xx'); // 第2个参数是api接口地址
// 3. 发送请求
xhr.send();
// 4. 处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
p.then(value=>{
console.log(value);
}, reason=>{
console.log(reason);
})
});
</script>
// v3.0 promise 封装 ajax
<script>
// 封装 sendAJAX函数 发送 GET AJAX 请求
function sendAJAX(){
return new Promise((resolve, reject)=>{
const xhr = XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
}
</script>
---
sendAJAX('https://api.xx') // api接口地址
.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
现实生活中的 Promise 模型和概念
一对男女朋友,女人承诺(new Promise)在2.14情人节的时候给男人送一个孩子作为情人节礼物,承诺会产生两种结果,成功怀孕(resolve)解决承诺,反之就是不成功(reject)拒绝承诺,不管成功与否,两人还是会在2.14情人节后结婚领证,也就是说成功与否这件事不是马上就知道结果的,需要一段时间才知道,以上就是Promise的基本形式,即回调的升级版,在处理一些花费比较长时间的任务时,使用Promise就可以进行异步的处理,防止阻塞。
情人节过后,实际只有女人知道结果,男人不得而知,女人心计一下,成功的话就称呼男人为孩子他爹,失败的话,她还称呼男人为老公,即可以为两种结果找到合适的理由(为resolve和reject里面传入参数,可以在后面使用)。揭晓结果时,如果成功,女人就会用then来表示,如果失败,女人就会用catch来表示,女人就会抱着男人不放,但最终还是结婚了,用finally来表示。
代码还原刚才的栗子
const isPregnant = true;
const promise = new Promise( (resolve, reject)=>{
if(isPregnant){
resolve(`孩子他爹`)
} else {
reject(`老公`)
}
} );
promise
.then( name=>{
console.log(`男人成为了${name}`);
})
.catch( name=>{
console.log(`男人成为了${name}!`);
})
.finally(()=>{
console.log(`男人和女人最终结婚了`);
})
// 输出结果为 ture时,男人成为了孩子他爹 男人和女人最终结婚了
// 输出结果为 false时,男人成为了老公 男人和女人最终结婚了
async / await
async 函数
函数的返回值为 promise 对象,其结果由 async 函数执行的返回值决定。与 then 方法的返回结果一致。
async 函数中可以没有 await,反之 await 必须在 async 函数中。
async function main(){
// 1. 返回值为 非 Promise 类型的数据
return 521; // 见 截图 1
// 2. 返回值为 Promise 对象
return new Promise((resolve, reject)=>{
resolve('OK'); // 见 截图 2
reject('Error'); // 见 截图 3
})
// 3. 抛出异常
throw 'error' // 见 截图 4
}
let result = main();
console.log(result);
await 表达式
await 右侧的表达式一般为 promise 对象(返回的是 promise 成功的值),也可以是其他的值(此值作为 await 的返回值)。
async function main(){
let p = new Promise((resolve, reject)=>{
resolve('OK');
// 情况3 reject('Error')
})
// 1. 右侧为 promise
let res = await p;
console.log(res); // 输出 OK
// 2. 右侧为 其他类型的数据
let res2 = await 20;
console.log(res2); // 输出 20
// 3. 如果 promise 是失败的状态
try{
let res3 = await p;
}catch(e){
console.log(e); // 输出 Error
}
}
async 与 await 结合发送 AJAX请求
<button id="btn">点击获取段子</button>
// 可用 axios 封装这个函数
function sendAJAX(url){
return new Promise((resolve, reject)=>{})
}
const btn = document.querySelector('#btn');
btn.addEventListener('click', async function(){
let duanzi = await sendAJAX('https://api.xxx');
console.log(duanzi);
})
axios
axios 是一个基于 promise 封装的网络请求库,它是基于 XHR 进行二次封装。
axios 是随着 Vue 的兴起而被广泛使用的,目前来说,绝大多数的 Vue 项目中的网络请求都是利用 Axios 发起的。当然它并不是一个思想,或者一个原生 API,它是一个封装库。
JSON Server 搭建 HTTP 服务
创建 full fake REST API
// 1. install
npm install -g json-server
// 2. Create a db.json file with some data
// 3. Start JSON Server
json-server --watch db.json
axios 是什么
Promise based HTTP client for the browser and node.js
axios 能干什么
- 发送 AJAX 请求(浏览器端)
- 发送 HTTP 请求(node.js端)
- 支持 Promise API
- 请求、响应拦截器(本质是函数。请求之前做准备工作,响应的结果预处理)
- 转换请求、响应的数据
- 取消请求
- 自动转换为JSON数据
安装 axios
npm install axios
yarn add axios
// cdn 引入
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios 基本使用
<button>发送GET请求</button>
const btns = document.querySelectorAll('button');
btns[0].onclick = function(){
axios({
method: 'GET',
url: '/user/12345',
}).then(response =>{
console.log(response)
})
}
<button>发送POST请求</button>
const btns = document.querySelectorAll('button');
btns[1].onclick = function(){
axios({
method: 'POST',
url: '/user/12345',
// 设置 请求体
data:{
title:"绝世好文",
author:"张三"
}
}).then(response =>{
console.log(response)
})
}
axios 其他方式发送请求
axios.request({
methods:'GET',
url:'https://xxx'
}).then(response =>{
console.log(response)
})
// 发送 POST 请求
axios.post(
'https://xxx',
{
"body":"hello",
"postId":2
}
).then(response =>{
console.log(response)
})
axios 响应结果
| 标题 | 内容 |
|---|---|
| config | method 请求类型 url 请求地址 请求体 |
| data 响应体的结果 | axios自动将服务器返回结果JSON解析为对象 |
| headers 响应头信息 | |
| request 原生 AJAX 请求对象 |
相关概念
| 标题 | 内容 | 备注 |
|---|---|---|
| 并发 | 代表计算机能够同时执行多项任务 | 单核处理器通过分配时间片 让任务执行一段时间 切换到另一个任务再运行一段时间 不同任务交替往复执行 |
| 并行 | 代表计算机能够同时执行多项任务 | 多核处理器在不同的核心上并行的执行任务 |
| 多线程编程 | 典型实现异步的方式 | 多核环境每个线程被分配到独立的核心上运行 应用于视频图像处理、科学计算 |
| 单线程编程 | 单个脚本只能在一个线程上运行 (主线程) | JS 引擎有多个线程 |
| 同步任务 Sync | 未被引擎挂起 在主线程上排队的任务 | 前一个任务执行完才能执行下个任务 也可理解为同步任务就是可以直接拿到结果 |
| 异步任务 Async | 被引擎挂起 不进入主线程而进入任务队列的任务 | 异步任务就是不能直接拿到结果 需要通过轮询或者回调来拿到结果 |
| 事件循环 | 循环检查异步任务是否可进入主线程的机制 | 挂起处于等待的任务 先执行排在后面的任务 等异步操作返回结果 再回头继续执行挂起的任务 |
| 任务队列 | JS 引擎提供的需要当前程序处理的异步任务 |
单线程
| JS 执行环境 | 内容 | 缺点 |
|---|---|---|
| 单线程 | 一次只能完成一件任务。 如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推 | 有耗时长的任务需排队 拖延程序执行 解决此问题的方案是 JS语言将任务的执行模式分为同步和异步 |