事件循环
JS运行的环境称之为宿主环境。
执行栈:call stack,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前,它的相关信息会加入到执行栈。函数调用之前,创建执行环境,然后加入到执行栈;函数调用之后,销毁执行环境。
JS引擎永远执行的是执行栈的最顶部。
异步函数:某些函数不会立即执行,需要等到某个时机到达后才会执行,这样的函数称之为异步函数。比如事件处理函数。异步函数的执行时机,会被宿主环境控制。
浏览器宿主环境中包含5个线程:
- JS引擎:负责执行执行栈的最顶部代码
- GUI线程:负责渲染页面
- 事件监听线程:负责监听各种事件
- 计时线程:负责计时
- 网络线程:负责网络通信
当上面的线程发生了某些事请,如果该线程发现,这件事情有处理程序,它会将该处理程序加入一个叫做事件队列的内存。当JS引擎发现,执行栈中已经没有了任何内容后,会将事件队列中的第一个函数加入到执行栈中执行。
JS引擎对事件队列的取出执行方式,以及与宿主环境的配合,称之为事件循环。
事件队列在不同的宿主环境中有所差异,大部分宿主环境会将事件队列进行细分。在浏览器中,事件队列分为两种:
- 宏任务(队列):macroTask,计时器结束的回调、事件回调、http回调等等绝大部分异步函数进入宏队列
- 微任务(队列):MutationObserver,Promise产生的回调进入微队列
MutationObserver用于监听某个DOM对象的变化
当执行栈清空时,JS引擎首先会将微任务中的所有任务依次执行结束,如果没有微任务,则执行宏任务。
Promise 基础
问题的由来
邓哥的烦恼
邓哥心中有很多女神,他今天下定决心,要向这些女神表白,他认为,只要女神够多,根据概率学原理,总有一个会接收他
稳妥起见,邓哥决定使用串行的方式进行表白:先给第1位女神发送短信,然后等待女神的回应,如果成功了,就结束,如果失败了,则再给第2位女神发送短信,依次类推

邓哥的女神一共有4位,名字分别是:李建国、王富贵、周聚财、刘人勇
发短信是一个重复性的劳动,邓哥是个程序员,因此决定用函数封装这个动作
// 向某位女生发送一则表白短信
// name: 女神的姓名
// onFulffiled: 成功后的回调
// onRejected: 失败后的回调
function sendMessage(name, onFulffiled, onRejected) {
// 模拟 发送表白短信
console.log(
`邓哥 -> ${name}:最近有谣言说我喜欢你,我要澄清一下,那不是谣言😘`
);
console.log(`等待${name}回复......`);
// 模拟 女神回复需要一段时间
setTimeout(() => {
// 模拟 有10%的几率成功
if (Math.random() <= 0.1) {
// 成功,调用 onFuffiled,并传递女神的回复
onFulffiled(`${name} -> 邓哥:我是九,你是三,除了你还是你😘`);
} else {
// 失败,调用 onRejected,并传递女神的回复
onRejected(`${name} -> 邓哥:你是个好人😜`);
}
}, 1000);
}
有了这个函数后,邓哥于是开始编写程序发送短信了
// 首先向 李建国 发送消息
sendMessage(
'李建国',
(reply) => {
// 如果成功了,输出回复的消息后,结束
console.log(reply);
},
(reply) => {
// 如果失败了,输出回复的消息后,向 王富贵 发送消息
console.log(reply);
sendMessage(
'王富贵',
(reply) => {
// 如果成功了,输出回复的消息后,结束
console.log(reply);
},
(reply) => {
// 如果失败了,输出回复的消息后,向 周聚财 发送消息
console.log(reply);
sendMessage(
'周聚财',
(reply) => {
// 如果成功了,输出回复的消息后,结束
console.log(reply);
},
(reply) => {
// 如果失败了,输出回复的消息后,向 刘人勇 发送消息
console.log(reply);
sendMessage(
'刘人勇',
(reply) => {
// 如果成功了,输出回复的消息后,结束
console.log(reply);
},
(reply) => {
// 如果失败了,就彻底没戏了
console.log(reply);
console.log('邓哥命犯天煞孤星,注定孤独终老!!');
}
);
}
);
}
);
}
);
该程序完成后,邓哥内心是崩溃的
这一层一层的回调嵌套,形成了传说中的「回调地狱 callback hell」
邓哥是个完美主义者,怎么能忍受这样的代码呢?
要解决这样的问题,需要Promise出马
Promise规范
Promise是一套专门处理异步场景的规范,它能有效的避免回调地狱的产生,使异步代码更加清晰、简洁、统一
这套规范最早诞生于前端社区,规范名称为Promise A+
该规范出现后,立即得到了很多开发者的响应
Promise A+ 规定:
-
所有的异步场景,都可以看作是一个异步任务,每个异步任务,在JS中应该表现为一个对象,该对象称之为Promise对象,也叫做任务对象
-
每个任务对象,都应该有两个阶段、三个状态
根据常理,它们之间存在以下逻辑:
- 任务总是从未决阶段变到已决阶段,无法逆行
- 任务总是从挂起状态变到完成或失败状态,无法逆行
- 时间不能倒流,历史不可改写,任务一旦完成或失败,状态就固定下来,永远无法改变
-
挂起->完成,称之为resolve;挂起->失败称之为reject。任务完成时,可能有一个相关数据;任务失败时,可能有一个失败原因。
-
可以针对任务进行后续处理,针对完成状态的后续处理称之为onFulfilled,针对失败的后续处理称之为onRejected

Promise API
ES6提供了一套API,实现了Promise A+规范
基本使用如下:
// 创建一个任务对象,该任务立即进入 pending 状态
const pro = new Promise((resolve, reject) => {
// 任务的具体执行流程,该函数会立即被执行
// 调用 resolve(data),可将任务变为 fulfilled 状态, data 为需要传递的相关数据
// 调用 reject(reason),可将任务变为 rejected 状态,reason 为需要传递的失败原因
});
pro.then(
(data) => {
// onFulfilled 函数,当任务完成后,会自动运行该函数,data为任务完成的相关数据
},
(reason) => {
// onRejected 函数,当任务失败后,会自动运行该函数,reason为任务失败的相关原因
}
);
邓哥的解决方案
学习了ES6的Promise后,邓哥决定对sendMessage函数进行改造,改造结果如下:
// 向某位女生发送一则表白短信
// name: 女神的姓名
// 该函数返回一个任务对象
function sendMessage(name) {
return new Promise((resolve, reject) => {
// 模拟 发送表白短信
console.log(
`邓哥 -> ${name}:最近有谣言说我喜欢你,我要澄清一下,那不是谣言😘`
);
console.log(`等待${name}回复......`);
// 模拟 女神回复需要一段时间
setTimeout(() => {
// 模拟 有10%的几率成功
if (Math.random() <= 0.1) {
// 成功,调用 resolve,并传递女神的回复
resolve(`${name} -> 邓哥:我是九,你是三,除了你还是你😘`);
} else {
// 失败,调用 reject,并传递女神的回复
reject(`${name} -> 邓哥:你是个好人😜`);
}
}, 1000);
});
}
之后,就可以使用该函数来发送消息了
sendMessage('李建国').then(
(reply) => {
// 女神答应了,输出女神的回复
console.log(reply);
},
(reason) => {
// 女神拒绝了,输出女神的回复
console.log(reason);
}
);
至此,回调地狱的问题仍然没能解决
要解决回调地狱,还需要进一步学习Promise的知识

catch方法
.catch(onRejected) = .then(null, onRejected)
链式调用

-
then方法必定会返回一个新的Promise
可理解为
后续处理也是一个任务 -
新任务的状态取决于后续处理:
-
若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据
-
若有后续处理但还未执行,新任务挂起。
-
若后续处理执行了,则根据后续处理的情况确定新任务的状态
- 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值
- 后续处理执行有错,新任务的状态为失败,数据为异常对象
- 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致
-
由于链式任务的存在,异步代码拥有了更强的表达力
// 常见任务处理代码
/*
* 任务成功后,执行处理1,失败则执行处理2
*/
pro.then(处理1).catch(处理2)
/*
* 任务成功后,依次执行处理1、处理2
*/
pro.then(处理1).then(处理2)
/*
* 任务成功后,依次执行处理1、处理2,若任务失败或前面的处理有错,执行处理3
*/
pro.then(处理1).then(处理2).catch(处理3)
面试题
1.第一题
const pro1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
const pro2 = pro1.then((data) => {
console.log(data);
return data + 1;
});
const pro3 = pro2.then((data) => {
console.log(data);
});
console.log(pro1, pro2, pro3);
setTimeout(() => {
console.log(pro1, pro2, pro3);
}, 2000);
- 第二题
new Promise((resolve, reject) => {
resolve(1);
})
.then((res) => {
console.log(res);
return 2;
})
.catch((err) => {
return 3;
})
.then((res) => {
console.log(res);
});
总结几种情况:
执行算成功还是算失败?
- 正常执行语句,没有调用resolve,reject语句,如果代码执行没有报错,则Promise 的状态为fulfilled.
- 如果执行过程中 throw new Error(),则执行失败,则Promise 的状态为rejected.return new Error('2') 并不算执行报错,只是返回一个error,并非代码执行报错。
- 即便没有throw new Error(),但是比方说下面undefied..toString()代码执行出错,则Promise 的状态为rejected.
- 如果代码中有多个 resolve,reject,只看第一个,后面的resolve,reject就相当于没有,代码仍然会往下执行完。
const pro1 = new Promise((resolve, reject) => {
resolve(1);
reject(1);
resolve(3);
console.log(1);
throw new Error(1);
return new Error('2');
var a;
console.log(a.toString());
});
前面的任务挂起,后面的所有任务的状态都是挂起。
前面的任务失败,近接着的则Promise只看失败的处理,无视成功的处理;前面的任务成功,近接着的则Promise只看成功的处理,无视失败的处理
邓哥的解决方案
// 向某位女生发送一则表白短信
// name: 女神的姓名
// onFulffiled: 成功后的回调
// onRejected: 失败后的回调
function sendMessage(name) {
return new Promise((resolve, reject) => {
// 模拟 发送表白短信
console.log(
`邓哥 -> ${name}:最近有谣言说我喜欢你,我要澄清一下,那不是谣言😘`
);
console.log(`等待${name}回复......`);
// 模拟 女神回复需要一段时间
setTimeout(() => {
// 模拟 有10%的几率成功
if (Math.random() <= 0.1) {
// 成功,调用 onFuffiled,并传递女神的回复
resolve(`${name} -> 邓哥:我是九,你是三,除了你还是你😘`);
} else {
// 失败,调用 onRejected,并传递女神的回复
reject(`${name} -> 邓哥:你是个好人😜`);
}
}, 1000);
});
}
sendMessage('李建国')
.catch((reply) => {
// 失败,继续
console.log(reply);
return sendMessage('王富贵');
})
.catch((reply) => {
// 失败,继续
console.log(reply);
return sendMessage('周聚财');
})
.catch((reply) => {
// 失败,继续
console.log(reply);
return sendMessage('刘人勇');
})
.then(
(reply) => {
// 成功,结束
console.log(reply);
console.log('邓哥终于找到了自己的伴侣');
},
(reply) => {
// 最后一个也失败了
console.log(reply);
console.log('邓哥命犯天煞孤星,无伴终老,孤独一生');
}
);
邓哥的新问题
邓嫂出门时,给邓哥交待了几个任务:
-
做饭
可交给电饭煲完成
-
洗衣服
可交给洗衣机完成
-
打扫卫生
可交给扫地机器人完成
邓哥需要在所有任务结束后给邓嫂汇报工作,哪些成功了,哪些失败了
为了最大程度的节约时间,邓哥希望这些任务同时进行,最终汇总结果统一处理
每个任务可以看做是一个返回Promise的函数
// 做饭
function cook() {
return new Promise((resolve, reject) => {
console.log('邓哥打开了电饭煲');
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('饭已ok');
} else {
reject('做饭却忘了加水,米饭变成了爆米花');
}
}, 2000);
});
}
// 洗衣服
function wash() {
return new Promise((resolve, reject) => {
console.log('邓哥打开了洗衣机');
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('衣服已经洗好');
} else {
reject('洗衣服时停水了,洗了个寂寞');
}
}, 2500);
});
}
// 打扫卫生
function sweep() {
return new Promise((resolve, reject) => {
console.log('邓哥打开了扫地机器人');
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('地板扫的非常干净');
} else {
reject('扫地机器人被哈士奇一爪掀翻了');
}
}, 3000);
});
}
如何利用这三个函数实现邓哥的要求呢?
Promise的静态方法
| 方法名 | 含义 |
|---|---|
| Promise.resolve(data) | 直接返回一个完成状态的任务 |
| Promise.reject(reason) | 直接返回一个拒绝状态的任务 |
| Promise.all(任务数组) | 返回一个任务 任务数组全部成功则成功 任何一个失败则失败 |
| Promise.any(任务数组) | 返回一个任务 任务数组任一成功则成功 任务全部失败则失败 |
| Promise.allSettled(任务数组) | 返回一个任务 任务数组全部已决则成功 该任务不会失败 |
| Promise.race(任务数组) | 返回一个任务 任务数组任一已决则已决,状态和其一致 |
邓哥的解决方案
Promise.allSettled([cook(), wash(), sweep()]).then((result) => {
// 处理汇总结果
const report = result
.map((r) => (r.status === 'fulfilled' ? r.value : r.reason))
.join(';');
console.log(report);
});

消除回调
有了Promise,异步任务就有了一种统一的处理方式
有了统一的处理方式,ES官方就可以对其进一步优化
ES7推出了两个关键字async和await,用于更加优雅的表达Promise
async
async关键字用于修饰函数,被它修饰的函数,一定返回Promise
async function method1(){
return 1; // 该函数的返回值是Promise完成后的数据
}
method1(); // Promise { 1 }
async function method2(){
return Promise.resolve(1); // 若返回的是Promise,则method得到的Promise状态和其一致
}
method2(); // Promise { 1 }
async function method3(){
throw new Error(1); // 若执行过程报错,则任务是rejected
}
method3(); // Promise { <rejected> Error(1) }
await
await关键字表示等待某个Promise完成,它必须用于async函数中
async function method(){
const n = await Promise.resolve(1);
console.log(n); // 1
}
// 上面的函数等同于
function method(){
return new Promise((resolve, reject)=>{
Promise.resolve(1).then(n=>{
console.log(n);
resolve(1)
})
})
}
await也可以等待其他数据
async function method(){
const n = await 1; // 等同于 await Promise.resolve(1)
}
如果需要针对失败的任务进行处理,可以使用try-catch语法
async function method(){
try{
const n = await Promise.reject(123); // 这句代码将抛出异常
console.log('成功', n)
}
catch(err){
console.log('失败', err)
}
}
method(); // 输出: 失败 123
邓哥表白的完美解决方案
邓哥的女神可不是只有4位,而是40位!
为了更加方便的编写表白代码,邓哥决定把这40位女神放到一个数组中,然后利用async和await轻松完成代码
// 女神的名字数组
const beautyGirls = [
'梁平',
'邱杰',
'王超',
'冯秀兰',
'赖军',
'顾强',
'戴敏',
'吕涛',
'冯静',
'蔡明',
'廖磊',
'冯洋',
'韩杰',
'江涛',
'文艳',
'杜秀英',
'丁艳',
'邓静',
'江刚',
'乔刚',
'史平',
'康娜',
'袁磊',
'龙秀英',
'姚静',
'潘娜',
'萧磊',
'邵勇',
'李芳',
'谭芳',
'夏秀英',
'程娜',
'武杰',
'崔军',
'廖勇',
'崔强',
'康秀英',
'余磊',
'邵勇',
'贺涛',
];
// 向某位女生发送一则表白短信
// name: 女神的姓名
function sendMessage(name) {
return new Promise((resolve, reject) => {
// 模拟 发送表白短信
console.log(
`邓哥 -> ${name}:最近有谣言说我喜欢你,我要澄清一下,那不是谣言😘`
);
console.log(`等待${name}回复......`);
// 模拟 女神回复需要一段时间
setTimeout(() => {
// 模拟 有10%的几率成功
if (Math.random() <= 0.1) {
// 成功,调用 onFuffiled,并传递女神的回复
resolve(`${name} -> 邓哥:我是九,你是三,除了你还是你😘`);
} else {
// 失败,调用 onRejected,并传递女神的回复
reject(`${name} -> 邓哥:你是个好人😜`);
}
}, 1000);
});
}
// 批量表白的程序
async function proposal() {
let isSuccess = false;
for (const girl of beautyGirls) {
try {
const reply = await sendMessage(girl);
console.log(reply);
console.log('表白成功!');
isSuccess = true;
break;
} catch (reply) {
console.log(reply);
console.log('表白失败');
}
}
if (!isSuccess) {
console.log('邓哥注定孤独一生');
}
}
proposal();
面试题考点
Promise的基本概念

链式调用规则


-
then方法必定会返回一个新的Promise
可理解为
后续处理也是一个任务 -
新任务的状态取决于后续处理:
-
若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据
-
若有后续处理但还未执行,新任务挂起。
-
若后续处理执行了,则根据后续处理的情况确定新任务的状态
- 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值
- 后续处理执行有错,新任务的状态为失败,数据为异常对象
- 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致
自己的理解:如果前面任务成功了,后续任务也成功了,则最后一个promise是成功的。如果前面的任务处理失败了,后续对失败的处理没有没有问题,则最后一个promise的状态也是成功的。如果前面一个promise成功,紧接着的then只找到成功的处理,而紧接着失败的处理则不管。
-
何为失败呢? 1.调用了 reject 2.执行过程出错了,包括抛出异常 throw error, 代码执行过程中报了其他错误。
Promise的静态方法
| 方法名 | 含义 |
|---|---|
| Promise.resolve(data) | 直接返回一个完成状态的任务 |
| Promise.reject(reason) | 直接返回一个拒绝状态的任务 |
| Promise.all(任务数组) | 返回一个任务 任务数组全部成功则成功 任何一个失败则失败 |
| Promise.any(任务数组) | 返回一个任务 任务数组任一成功则成功 任务全部失败则失败 |
| Promise.allSettled(任务数组) | 返回一个任务 任务数组全部已决则成功 该任务不会失败 |
| Promise.race(任务数组) | 返回一个任务 任务数组任一已决则已决,状态和其一致 |
async和await
有了Promise,异步任务就有了一种统一的处理方式
有了统一的处理方式,ES官方就可以对其进一步优化
ES7推出了两个关键字async和await,用于更加优雅的表达Promise
async
async关键字用于修饰函数,被它修饰的函数,一定返回Promise
async function method1(){
return 1; // 该函数的返回值是Promise完成后的数据
}
method1(); // Promise { 1 }
async function method2(){
return Promise.resolve(1); // 若返回的是Promise,则method得到的Promise状态和其一致
}
method2(); // Promise { 1 }
async function method3(){
throw new Error(1); // 若执行过程报错,则任务是rejected
}
method3(); // Promise { <rejected> Error(1) }
await
await关键字表示等待某个Promise完成,它必须用于async函数中
async function method(){
const n = await Promise.resolve(1);
console.log(n); // 1
}
// 上面的函数等同于
function method(){
return new Promise((resolve, reject)=>{
Promise.resolve(1).then(n=>{
console.log(n);
resolve(1)
})
})
}
await也可以等待其他数据
async function method(){
const n = await 1; // 等同于 await Promise.resolve(1)
}
如果需要针对失败的任务进行处理,可以使用try-catch语法
async function method(){
try{
const n = await Promise.reject(123); // 这句代码将抛出异常
console.log('成功', n)
}
catch(err){
console.log('失败', err)
}
}
method(); // 输出: 失败 123
事件循环
根据目前所学,进入事件队列的函数有以下几种:
setTimeout的回调,宏任务(macro task)setInterval的回调,宏任务(macro task)- Promise的
then函数回调,微任务(micro task) requestAnimationFrame的回调,宏任务(macro task)- 事件处理函数,宏任务(macro task)
面试题
-
下面代码的输出结果是什么
const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); }) promise.then(() => { console.log(3); }) console.log(4);输出 1 2 4 3
-
下面代码的输出结果是什么
const promise = new Promise((resolve, reject) => { console.log(1); setTimeout(()=>{ console.log(2) resolve(); console.log(3); }) }) promise.then(() => { console.log(4); }) console.log(5);
输出 1 5 2 3 4 详细分析下:首先执行 console.log(1); 输出1,然后执行setTimeout,因为没有写时间,代表计时立即到了,然后将任务加入到宏任务里面。
开始往下执行,然后执行promise.then,只有promise的状态改变才会将任务加入到伪队列里面,此时里面的代码不会执行。
继续执行console.log(5);输出5.当前执行栈的代码执行完毕。
由于伪队列里面没有东西,开始执行宏任务里面的代码,先执行setTimeout里面的代码。 console.log(2) 执行完输出 2,resolve(); 此时promise的状态发生了改变,将console.log(4);加入到伪队列,继续在当前栈执行代码,执行console.log(3);输出3。当前栈执行完了,继续取微队列和宏队列里面的去找代码执行,去执行微队列里面的任务console.log(4);
- 下面代码输出什么?
setTimeout(() => {
console.log(1);
});
const promise = new Promise((resolve, reject) => {
console.log(2);
resolve();
});
promise.then(() => {
console.log(3);
});
console.log(4);
分析如下:
setTimeout 执行完后将console.log(1);加入到宏任务;
new Promise 执行完输出 2, promise状态改为fullfiled;
promise.then,执行将里面的代码加入到伪队列里面去;
console.log(4); 执行输出4,当前执行栈的代码执行完成。
去微队列和宏队列里面找代码去执行,先执行伪队列里面的代码console.log(3);输出3
再去宏队列里面的去找执行代码console.log(1);
最后的输出结果是 2 4 3 1
-
下面代码的输出结果是什么
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve() }, 1000) }) const promise2 = promise1.catch(() => { return 2; }) console.log('promise1', promise1) console.log('promise2', promise2) setTimeout(() => { console.log('promise1', promise1) console.log('promise2', promise2) }, 2000)
输出
promise1 Promise { }
promise2 Promise { }
promise1 Promise { undefined }
promise2 Promise { 2 }
-
下面代码的输出结果是什么
async function m(){ console.log(0); const n = await 1; console.log(n); } m(); console.log(2);
输出 0 2 1
上面的代码,执行m()的时候,给n赋值,和console.log(n);本质是在一个微队列里面。所以先输出0.然后当前栈的剩余代码 console.log(2);输出2,执行完当前调用栈的代码。去微队列里面执行代码,输出1.
-
下面代码的输出结果是什么
async function m(){ console.log(0); const n = await 1; console.log(n); } (async ()=>{ await m(); console.log(2); })(); console.log(3);输出 0 3 1 2
一开始是函数的声明
await m(); console.log(2); })();执行这句代码,await m();会先执行m函数的代码。然后执行console.log(0); 输出 0,代码继续执行await 1;然后给n的赋值,和后面的console.log(n);加入到微队列里面。然后只有上面的代码执行完才能执行console.log(2);执行执行当前栈的东西console.log(3);输出3.
执行栈的代码执行完后去微队列里面执行,执行上面的给n赋值,和console.log(n);输出1,最后输出伪队列里面的console.log(2);输出2. -
下面代码的输出结果是什么
async function m1(){ return 1; } async function m2(){ const n = await m1(); console.log(n) return 2; } async function m3(){ const n = m2(); console.log(n); return 3; } m3().then(n=>{ console.log(n); }); m3(); console.log(4);

微队列里面的任务是根据先后执行的顺序一个一个加入进去的。 这里面有一个关键点就是如何判断下面的async函数执行完了呢?也就是promise的状态改变了呢, 是要等里面的代码执行完才能判定。对于下面的代码也就是return 2执行完才知道
async function m2(){
const n = await m1();
console.log(n)
return 2;
}
8. 下面代码的输出结果是什么
```js
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
```
输出 1
是因为上面的Promise里面then方法要传进去一个回调函数,如果不是的话,就相当于没写,而 2 不是一个函数,Promise.resolve(3)是一个promise对象,也不是一个函数。console.log 是一个函数,可以执行。
-
下面代码的输出结果是什么
var a; var b = new Promise((resolve, reject) => { console.log('promise1'); setTimeout(()=>{ resolve(); }, 1000); }).then(() => { console.log('promise2'); }).then(() => { console.log('promise3'); }).then(() => { console.log('promise4'); }); a = new Promise(async (resolve, reject) => { console.log(a); await b; console.log(a); console.log('after1'); await a resolve(true); console.log('after2'); }); console.log('end');

- 下面代码的输出结果是什么
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');

后面的输出还有微队列的东西,宏队列的东西。