基础定义
promise
Promise
对象是由关键字new
及其构造函数来创建的。
该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。
这个“处理器函数”接受两个函数——resolve
和reject
——作为其参数。
当异步任务顺利完成且返回结果值时,会调用 resolve 函数
;
而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数
async
当调用一个
async
函数时,会返回一个 promise 对象
当这个异步函数返回一个值时,async 通过 Promise.resolve() 将这个值封装成 promise 对象
当这个异步函数没有返回值时,会返回 Promise.resolve(undefined)
当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值
async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待 Promise 的结果出来,然后恢复async函数的执行并返回解析值(resolved
注意:Promise 的特点——无等待
,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致
await
await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
语法:[return_value] = await expression;
expression 是一个 Promise 对象或者任何要等待的值。返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
await 表达式会暂停
当前 async function 的执行,等待 Promise 处理完成。
若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。
若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。
另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。
注意重点:很多人以为await会一直等待之后的表达式执行完之后才会继续执行后面的代码, 实际上await是一个让出线程的标志。await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈的代码。
等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值
如果返回值为非 promise 则继续执行 async 函数后面的代码,否则将返回的 promise 放入 promise 队列(Promise的Job Queue)
执行机制
- 首先我们知道
js
是单线程
语言,任务可以分为同步任务,异步任务,当然也可以分为宏任务,微任务。
任务 | 举例 |
---|---|
宏任务 | 整体js代码、setTimeout、setInterval等 |
微任务 | Promise,process.nextTick等 |
-
执行机制(event loop)
- 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
- 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
- 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
-
事件循环、宏任务、微任务关系图
实例讲解
下面举个栗子:
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');
打印结果为:
script start
async1 start
asynic2
promise1
script end
async1 end
promise2
setTimeout
具体解释:
整体代码作为宏任务(同步任务)
从上至下执行,首先打印script start- 遇到setTimeout异步任务,那么
将其回调函数注册后分发到宏任务Event Queue
- 接下来遇到
async function
,打印async1 start - 执行
await
后面的async2(),打印出asynic2,产生一个微任务,分发到Event Queue,等待返回一个promise.resolve(undefined) new Promise
立即执行打印promise1,产生一个微任务,分发到Event queue,等待返回一个promise.resolve()- 打印script end,同步任务首次结束,下面执行异步任务
- 先看Event queue 队列里面是否有微任务,如果存在首先执行微任务,打印async1 end
- 然后继续打印 promise2
- 最后打印出event queue 队列里面的宏任务,打印出 setTimeout
尝试解释下面这段代码吧
async function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
}
test();
var promise = new Promise(
(resolve) => {
console.log("promise start..");
resolve("promise");
}
);
promise.then((val)=> { console.log(val) });
console.log("test end...")
参考文章: