JavaScript宏观任务和微观任务
JavaScript代码在执行的时候,可以说就是拿一段代码给到JavaScript引擎并去执行,此外还可能会提供额外的API给到JavaScript引擎。
在ES3 或者 更早的版本中,JavaScript并无异步操作,所以代码给到JavaScript引擎,它就直接顺次的执行,这个任务是宿主发起的任务我们可以称之为宏观任务(macrotask)。
在ES5 或者 之后的版本,JavaScript出现了Promise,这就不需要浏览器的安排,引擎自己也可以发起任务,这个任务就叫做微观任务(microtask)
image.pngPromise
MDN解释:Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。
基本用法:
function sleep(duration) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}
sleep(1000)
.then( ()=> console.log("then"))
.catch( ()=> console.log('catch') )
.finally( () => console.log('finally'));
Promise.prototype.catch(onRejected)
添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果.
Promise.prototype.then(onFulfilled, onRejected)
添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
Promise.prototype.finally(onFinally)
添加一个事件处理回调于当前promise对象,并且在原promise对象解析完毕后,返回一个新的promise对象。回调会在当前promise运行完毕后被调用,无论当前promise的状态是完成(fulfilled)还是失败(rejected)
function sleep(duration) {
return new Promise(function(resolve, reject) {
console.log("b");
setTimeout(resolve,duration);
})
}
console.log("a");
sleep(5000).then(()=>console.log("c"));
setTimeout 是属于宿主环境的api,属于宏观任务,所以可以分析为两个宏观任务,但是setTimeout中带有一个微观任务。所以执行结果为a b c
async/await
当调用一个 async
函数时,会返回一个 Promise
对象。当这个 async
函数返回一个值时,Promise
的 resolve 方法会负责传递这个值;当 async
函数抛出异常时,Promise
的 reject 方法也会传递这个异常值。
async
函数中可能会有 await
表达式,这会使 async
函数暂停执行,等待 Promise
的结果出来,然后恢复async
函数的执行并返回解析值(resolved)。
注意, await
关键字仅仅在 async
function中有效。如果在 async function
函数体外使用 await
,你只会得到一个语法错误(对象代表尝试解析语法上不合法的代码的错误。)。
var resolveAfter2Seconds = function() {
console.log("starting slow promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("fast promise is done");
}, 1000);
});
};
var sequentialStart = async function() {
console.log('==SEQUENTIAL START==');
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. this runs 3 seconds after 1.
}
var concurrentStart = async function() {
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second(); // starts timer immediately
// 1. Execution gets here almost instantly
console.log(await slow); // 2. this runs 2 seconds after 1.
console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
var concurrentPromise = function() {
console.log('==CONCURRENT START with Promise.all==');
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
});
}
var parallel = async function() {
console.log('==PARALLEL with await Promise.all==');
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
]);
}
// This function does not handle errors. See warning below!
var parallelPromise = function() {
console.log('==PARALLEL with Promise.then==');
resolveAfter2Seconds().then((message)=>console.log(message));
resolveAfter1Second().then((message)=>console.log(message));
}
sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast"
// wait above to finish
setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast"
// wait again
setTimeout(concurrentPromise, 7000); // same as concurrentStart
// wait again
setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow"
// wait again
setTimeout(parallelPromise, 13000); // same as parallel