目录
JS引擎
当前,最流行的JavaScript 引擎是谷歌的 V8 引擎,chrome和node用的都是v8引擎,其包含两个部分:
- 内存堆(Memory Heap):内存分配发生的地方。当V8引擎遇到变量声明和函数声明的时候,就把它们存储在堆里面。
- 调用栈(Callback Stack):代码执行时的地方。当引擎遇到像函数调用之类的可执行单元,就会把它们推入调用栈。JS单线程(只有一个主线程)指的是执行JS代码的调用栈是唯一的。
*注意:栈存放的空间是有限的,存放过多调用函数会造成栈溢出。
JS单线程
JS执行栈是单线程,但是JS的宿主环境不是单线程的(如浏览器、Node),浏览器内部是允许多个线程同时运行的,除JavaScript引擎线程外,还有事件触发线程、HTTP请求线程、定时器触发线程。他们和JavaScript线程是互不影响的,不会造成阻塞,JS执行的线程(即JavaScript引擎的所在线程)为主线程。
JS运行时

- Web API:异步函数调用时,调用函数可以从stack弹出,移到Web API。异步函数达到触发条件时,就把回调函数推入回调队列中。
- 回调队列:按照先进先出的顺序存储所有的回调函数。
- 事件循环:持续的检测调用栈和回调队列,如果检测到调用栈为空,它就会通知回调队列把队列中的第一个回调函数推入调用栈。
JS异步操作
JS的异步操作需要用到回调机制,为了给异步编程提供统一接口,JS提供了Promise规范,实现了回调函数的链式写法。
Promise对象
Promise是ES6中提出的一种异步解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。(详情查看)
Promise对象有三个状态(函数):
- pending(进行中,未完成):Promise对象的初始状态,result值为undefined。
- resolved(已完成):pending -> resolved
- rejected(已失败):pending -> rejected
异步事件完成后,状态发生改变,可以通过resolve/reject回调函数来传递result值(异步事件的返回值)。
promise.then(resolve, reject)
Promise提供了then方法来添加状态改变时的回调函数,可传递两种回调函数作为then的参数:
- 成功回调函数:resolve
- 失败回调函数:reject
以上回调函数中的传参为result值。
const URL = "https://v1.jirishici.com/all.json";
const promise = new Promise((resolved, reject) => {
// async code
const xhr = new XMLHttpRequest(); // 建立请求
xhr.open('GET', URL, true); // true表示为异步请求
xhr.onload = () => {
// if success: 响应成功后执行
resolved(xhr.responseText); // pending -> resolved/fullfilled
}
xhr.onerror = () => {
// if error:
reject('async error'); // pending -> rejected
}
xhr.send(); //发送请求
});
promise.then(
(result) => { // result/err是由promise执行返回的结果
console.log(result)
},
(err) => {
console.log(err)
});
*注意:then方法返回的是一个新的Promise实例。
还有一个catch方法,其实是then(null, rejection)的别名,用于指定发生错误时的回调函数。
const promise = new Promise(function(resolve, reject) {
...
});
promise.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
promise.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
资源获取
XMLHttpRequest
XMLHttpRequest 是一个内建的浏览器对象,它允许使用 JavaScript 发送 HTTP 请求。我们可以用它来上传/下载文件,跟踪进度等。前往这里了解更多。
// 1. 创建一个 new XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
// 2. 配置它:从 URL /article/.../load GET-request
xhr.open('GET', '/article/xmlhttprequest/example/load');
// 可以设置返回数据类型为json
xhr.responseType = 'json';
// 3. 通过网络发送请求
xhr.send();
// 4. 当接收到响应后,将调用此函数
xhr.onload = function() {
if (xhr.status != 200) { // 分析响应的 HTTP 状态
alert(`Error ${xhr.status}: ${xhr.statusText}`); // 例如 404: Not Found
} else { // 显示结果
alert(`Done, got ${xhr.response.length} bytes`); // response 是服务器响应
}
};
xhr.onerror = function() {
alert("Request failed");
};
Fetch
fetch的出现使得 XMLHttpRequest 在某种程度上被弃用。
fetch实质上也是一个Promise,其通用格式为fetch().then().then().catch()。(详情查看)
第一个then处理返回的response,可以返回一个Promise对象:
.then(response => {
return response.json();
})
第二个then处理第一个then返回的Promise对象所返回的result:
.then(reuslt => {
console.log(result);
})
catch()用于捕获失败的状态,可写可不写。
fetch(URL)
.then(response => {
console.log("fetch response: " + response);
return response.json(); // 返回一个Promise对象
})
.then(result => {
console.log("fetch result: " + result);
})
.catch(err => {
console.log("fetch err:" + err);
})
axios
axios对于请求和响应的处理作了一些自动化的优化设计。较XMLHttpRequest和fetch更为常用。
自动解析返回的数据类型
不同于fetch()返回的数据类型为stream,需要手动转换格式,axios能自动将数据解析成一个正常的js对象(例如json)。
const getData = () => {
axios.get("https://reqres.in/api/users").then(response => {
console.log(response);
})
};
const sendData = () => {
axios.post("https://reqres.in/api/register", {
email: "eve.hotl@reqres.in",
// password: "pistol"
}).then(response => {
console.log(response);
}).catch(error => {
console.log(error);
});
}
从sendData的返回可以看出,Header的“Content-Type: application/json”被自动添加了(fetch中需要手动设置才能返回正常的json对象)。
自动捕获返回的错误状态码
另外,当response返回一个error status code(例如400、500)的时候,axios能够自动分辨并让它作为一个能被捕获的error,而不需要在response的回调函数里面判断响应的返回是否处于error status(fectch中需要判断,因为请求是响应成功的,只不过返回值是error)。
保证异步执行顺序
async/await
异步操作不能确定代码块的先后执行(不确定哪一个事件会被先触发)。
例如:先后发送请求A、B,如果请求B先得到响应,那么请求B的回调会被先触发。
async/await有助于改进JS中异步操作串行的执行组织方式(确保执行顺序如愿)。(详情查看)
const fetchApi = async (url) => {
const response = await fetch(url); // 等待fetch来的Promise对象
const result = await response.json();
console.log(result);
}
如果出现error的情况,可以写作:
const fetchApi = async (url) => {
try {
const response = await fetch(url);
const result = await response.json();
console.log(result);
} catch (err) {
console.log(err);
}
}