Promise对象介绍
- Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
- 有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称’回调地狱’)
- ES6的Promise是一个构造函数, 用来生成promise实例
JS执行顺序问题
https://www.cnblogs.com/fundebug/p/tasks-microtasks-queues-and-schedules.html
每个“线程”都有自己的事件循环,因此每个 web worker 都有自己的事件循环,因此可以独立执行,而来自同域的所有窗口共享一个事件循环,所以它们可以同步地通信。
事件循环持续运行,直到清空 Tasks 队列的任务。一个事件循环有多个任务源,这些任务源保证了该源中的执行顺序(比如IndexedDB定义了它们自己的规范),但是浏览器可以在每次循环中选择哪个源来执行任务。这允许浏览器优先选择性能敏感的任务,比如用户输入等。
Tasks 被放到任务源中,这样浏览器就可以从内部进入JavaScript/DOM领域,并确保这些操作按顺序进行。在Tasks 执行期间,浏览器可能更新渲染。从鼠标点击到事件回调需要调度一个任务,解析超文本标记语言也是如此。
微任务通常是针对当前执行脚本之后应该立即发生的事情进行调度的,比如对一批操作进行响应,或者在不影响整个新任务的情况下进行异步处理。
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
Promise.resolve()
.then(function() {
console.log("promise1");
})
.then(function() {
console.log("promise2");
});
console.log("script end");
使用inner标签点击事件进行冒泡触发outer的执行顺序和输出情况
微任务在侦听器回调之间运行
使用.click()时间直接进行触发进行冒泡触发outer的执行顺序和输出情况
.click()会导致事件同步调度,因此调用.click()的脚本仍然在回调之间的堆栈中。
上述规则确保微任务不会中断执行中期的JavaScript。
这意味着我们不处理侦听器回调之间的微任务队列,它们在两个侦听器之后处理。
promise对象的3个状态
- pending: 初始化状态
- fullfilled: 成功状态
- rejected: 失败状态
解决回调地狱问题
//回调地狱案例
$.ajax{
url:'url1',
success:result=>{
$.ajax{
url:'url2',
success:result=>{
$.ajax{
url:'url3',
success:result=>{
}
};
}
};
}
};
//基于Promise解决方案
//封装成多个方法
let queryA = function(){
return new Promise(resolve=>{
$.ajax({
url:'url1',
success:resolve,
});
});
}
let queryB = function(){
return new Promise(resolve=>{
$.ajax({
url:'url2',
success:resolve,
});
});
}
let queryC = function(){
return new Promise(resolve=>{
$.ajax({
url:'url3',
success:resolve,
});
});
}
//先将queryA返回的实例赋给promise,每次执行then都会返回新的Prmise实例
let promise = queryA();
promise.then(result=>{
console.log(1);
return queryB();//将queryB的实例返回作为下一个的实例用于调用下一个then
}).then(result=>{
console.log(2);
return queryC();
}).then(result=>{
console.log(3);
});
new Promise和Promise.resolve的区别
let v = new Promise(resolve => {
console.log("begin")
resolve("then")
});
// 模式一 new Promise里的resolve()
// begin->1->2->3->then->4 可以发现then推迟了两个时序
// 推迟原因:浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例,这是一个微任务。
// 等到下次循环到来这个微任务会执行,也就是PromiseResolveThenableJob 执行中的时候,因为这个Promise 实例是fulfilled状态,所以又会注册一个它的.then()回调
// 又等一次循环到这个Promise 实例,它的.then()回调执行后,才会注册下面的这个.then(),于是就被推迟了两个时序
new Promise(resolve => {
resolve(v);
}).then(v =>{
console.log(v)
})
// 模式二 Promise.resolve(v)直接创建
// begin->1->then->2->3->4 可以发现then的执行时间正常了,第一个执行的微任务就是下面这个.then
// 原因:Promise.resolve()API如果参数是promise会直接返回这个promise实例,不会做任何处理
Promise.resolve(v).then((v)=>{
console.log(v)
});
new Promise(resolve => {
console.log(1);
resolve();
}).then(()=>{
console.log(2)
}).then(()=>{
console.log(3)
}).then(()=>{
console.log(4)
});
//链式调用测试
function Procedure() {
let p1 = Promise.resolve();
p1.then(function () {
//不管是走成功还是失败的回到函数,只要返回一个普通值(不抛出错误或者返回promise),都会执行下一个then的成功的回调
var a = setTimeout(function () {
console.log(1);
}, 2000)
console.log(a);//调用的时候就返回了一个值,所以直接进入到下一个then
}).then(function () {
//对then中的返回值进行异步,return中的异步resolve之后才能继续调用下一个then
new Promise(function (resolve, reject) {//如果then中返回了一个promise 会将promise的结果继续传给第二then中(如果结果是将状态改成成功就走下一个then的成功回调,状态改为失败就走下一个then的失败回调)
setTimeout(function () {
console.log(2);
//resolve或reject之后才会继续向下执行then
reject();
}, 2000)
})
}).then(function () {//给了then成功和失败回调then(success,error)
setTimeout(function () {
console.log(3);
}, 2000)
},function () {
setTimeout(function () {
console.log(4);
}, 2000)
}).catch(e=>{
console.log("catch");
})
}
//循环当中的异步递归逐个执行
function forin1() {
var menu = [{name: 'a', time: 2}, {name: 'b', time: 2}, {name: 'c', time: 2}, {name: 'd', time: 2}];
//声明一个循环用到的全局Pro
let p = Promise.resolve();
for (let i = 0; i < menu.length; i++) {
p = p.then(function() {
console.log(i)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(menu[i].name);
console.log(menu[i].name);
}, menu[i].time * 1000);
})
})
}
console.log(p)
}