JS中的同步异步编程
浏览器是多线程的,JS是单线程的(浏览器只分配一个线程来执行JS)
进程大线程小:一个进程中包含多个线程,例如在浏览器中打开一个HTML页面就占用了一个进程,加载页面的时候,浏览器分配一个线程去计算DOM树,分配其它的线程去加载对应的资源文件…再分配一个线程去自上而下执行JS
同步:在一个线程上(主栈/主任务队列)同一个时间只能做一件事情,当前事情完成才能进行下一个事情(先把一个任务进栈执行,执行完成,在把下一个任务进栈,上一个任务出栈…)
异步:在主栈中执行一个任务,但是发现这个任务是一个异步的操作,我们会把它移除主栈,放到等待任务队列中(此时浏览器会分配其它线程监听异步任务是否到达指定的执行时间),如果主栈执行完成,监听者会把到达时间的异步任务重新放到主栈中执行…
宏任务:macro task
- 定时器
- 事件绑定
- ajax
- 回调函数
- Node中fs可以进行异步的I/O操作
微任务:micro task
- Promise(async/await) => Promise并不是完全的同步,当在Excutor中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会再去调用resolve/reject把存放的方法执行
process.nextTick
执行顺序优先级:SYNC => MICRO => MACRO
所有JS中的异步编程仅仅是根据某些机制来管控任务的执行顺序,不存在同时执行两个任务这一说法
Promise A+
Promise 处理多个相互关联的异步请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23const request = url=>{
return new Promise((resolve,reject)=>{
$.get(url,data=>{ // jquery中的ajax请求
resolve(data);
})
})
}
request(url).then(data1=>{
return request(data1.url)
}).then(data2=>{
return request(data2.url)
}).then(data3=>{
return request(data3)
}).catch(err=>{
throw new Error(err.message)
})
-------------------------------------------------------
// vue/react 都是用axios fetch 请求数据 也都支持 Promise API
import axios from 'axios';
axios.get(url).then(data => {
console.log(data)
})
promise使用
- Promise 是一个构造函数,new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
1
2
3
4
5const promise = new Promise((resolve, reject) => {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
// promise相当于一个状态机
promise的三种状态
- pending
- fulfilled
- rejected
- promise 对象初始化状态为 pending
- 当调用resolve(成功),会由pending => fulfilled
- 当调用reject(失败),会由pending => rejected
注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变
promise对象方法
then方法注册 当resolve(成功)/reject(失败)的回调函数
1
2
3
4// onFulfilled 是用来接收promise成功的值
// onRejected 是用来接收promise失败的原因
promise.then(onFulfilled, onRejected);
// then方法是异步执行的resolve(成功) onFulfilled会被调用
1
2
3
4
5
6
7
8const promise = new Promise((resolve, reject) => {
resolve('fulfilled'); // 状态由 pending => fulfilled
});
promise.then(result => { // onFulfilled
console.log(result); // 'fulfilled'
}, reason => { // onRejected 不会被调用
})reject(失败) onRejected会被调用
1
2
3
4
5
6
7
8const promise = new Promise((resolve, reject) => {
reject('rejected'); // 状态由 pending => rejected
});
promise.then(result => { // onFulfilled 不会被调用
}, reason => { // onRejected
console.log(reason); // 'rejected'
})promise.catch
- 在链式写法中可以捕获前面then中发送的异常
1
2
3
4
5
6
7
8
9
10
11promise.catch(onRejected)
// 相当于
promise.then(null, onRrejected);
// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected);
// 可以写成:
promise.then(onFulfilled)
.catch(onRrejected);
- Promise chain链式调用
- promise.then方法每次调用 都返回一个新的promise对象 所以可以链式写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected) // 捕获前面then方法中的异常
- Promise的静态方法
Promise.resolve 返回一个fulfilled状态的promise对象
1
2
3
4
5
6
7
8
9Promise.resolve('hello').then(function(value){
console.log(value);
});
Promise.resolve('hello');
// 相当于
const promise = new Promise(resolve => {
resolve('hello');
});Promise.reject 返回一个rejected状态的promise对象
1
2
3
4Promise.reject(24);
new Promise((resolve, reject) => {
reject(24);
});
- Promise.all 接收一个promise对象数组为参数
- 只有全部为resolve才会调用 通常会用来处理 多个并行异步操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const p1 = new Promise((resolve, reject) => {
resolve(1);
});
const p2 = new Promise((resolve, reject) => {
resolve(2);
});
const p3 = new Promise((resolve, reject) => {
reject(3);
});
Promise.all([p1, p2, p3]).then(data => {
console.log(data); // [1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
console.log(err);
});
- Promise.race 接收一个promise对象数组为参数
- Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16unction timerPromisefy(delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
var startDate = Date.now();
Promise.race([
timerPromisefy(10),
timerPromisefy(20),
timerPromisefy(30)
]).then(function (values) {
console.log(values); // 10
});
- Promise的finally
1
2
3
4
5
6
7Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};