ref:《重学前端》
一个 JavaScript 引擎会常驻于内存中,它等待着我们(宿主)把 JavaScript 代码或者函数传递给它执行。
在ES3和更早的版本中,JavaScript本身还没有异步执行代码的能力,这也就意味着,宿主环境传递给JavaScript引擎一段代码,引擎就把代码直接顺次执行了,这个任务也就是宿主发起的任务。
但是,在ES5之后,JavaScript引入了Promise,这样,不需要浏览器的安排,JavaScript引擎本身也可以发起任务了。
Promise
基本用法
function sleep(duration) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}
sleep(1000).then( ()=> console.log("finished"));
再看下执行顺序
var r = new Promise(function(resolve, reject){
console.log("a");
resolve()
});
r.then(() => console.log("c"));
console.log("b")
上面输出是 a b c,在进入 console.log("b") 之前, r 已经得到了resolve,但是Promise的resolve始终是异步操作,所以c无法出现在b之前。
下面是 setTimeout 混合 Promise。
setTimeout(()=>console.log("d"), 0)
var r = new Promise(function(resolve, reject){
console.log("a");
resolve()
});
r.then(() => console.log("c"));
console.log("b")
输出是 a b c d,不论代码顺序如何,d必定发生在c之后,因为Promise产生的是JavaScript引擎内部的微任务,而setTimeout是浏览器API,它产生宏任务。
为了理解微任务始终先于宏任务,我们设计一个实验:执行一个耗时1秒的Promise。
setTimeout(()=>console.log("d"), 0)
var r = new Promise(function(resolve, reject){
resolve()
});
r.then(() => {
var begin = Date.now();
while(Date.now() - begin < 1000);
console.log("c1")
new Promise(function(resolve, reject){
resolve()
}).then(() => console.log("c2"))
});
这里我们强制了1秒的执行耗时,这样,我们可以确保任务c2是在d之后被添加到任务队列。
我们可以看到,即使耗时一秒的c1执行完毕,再enque的c2,仍然先于d执行了,这很好地解释了微任务优先的原理。
新特性:async/await
async/await是ES2016新加入的特性,它提供了用for、if等代码结构来编写异步的方式。它的运行时基础是Promise,先来看一下基本用法。
async函数必定返回Promise,我们把所有返回Promise的函数都可以认为是异步函数。
async函数是一种特殊语法,特征是在function关键字之前加上async关键字,这样,就定义了一个async函数,我们可以在其中使用await来等待一个Promise。
function sleep(duration) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}
async function foo(){
console.log("a")
await sleep(2000)
console.log("b")
}
async函数强大之处在于,它是可以嵌套的。我们在定义了一批原子操作的情况下,可以利用async函数组合出新的async函数。
function sleep(duration) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}
async function foo(name){
await sleep(2000)
console.log(name)
}
async function foo2(){
await foo("a");
await foo("b");
}
一个 JavaScript 引擎会常驻于内存中,它等待着我们(宿主)把 JavaScript 代码或者函数传递给它执行。
在ES3和更早的版本中,JavaScript本身还没有异步执行代码的能力,这也就意味着,宿主环境传递给JavaScript引擎一段代码,引擎就把代码直接顺次执行了,这个任务也就是宿主发起的任务。
但是,在ES5之后,JavaScript引入了Promise,这样,不需要浏览器的安排,JavaScript引擎本身也可以发起任务了。
Promise
基本用法
再看下执行顺序
上面输出是 a b c,在进入 console.log("b") 之前, r 已经得到了resolve,但是Promise的resolve始终是异步操作,所以c无法出现在b之前。
下面是 setTimeout 混合 Promise。
输出是 a b c d,不论代码顺序如何,d必定发生在c之后,因为Promise产生的是JavaScript引擎内部的微任务,而setTimeout是浏览器API,它产生宏任务。
为了理解微任务始终先于宏任务,我们设计一个实验:执行一个耗时1秒的Promise。
这里我们强制了1秒的执行耗时,这样,我们可以确保任务c2是在d之后被添加到任务队列。
我们可以看到,即使耗时一秒的c1执行完毕,再enque的c2,仍然先于d执行了,这很好地解释了微任务优先的原理。
新特性:async/await
async/await是ES2016新加入的特性,它提供了用for、if等代码结构来编写异步的方式。它的运行时基础是Promise,先来看一下基本用法。
async函数必定返回Promise,我们把所有返回Promise的函数都可以认为是异步函数。
async函数是一种特殊语法,特征是在function关键字之前加上async关键字,这样,就定义了一个async函数,我们可以在其中使用await来等待一个Promise。
async函数强大之处在于,它是可以嵌套的。我们在定义了一批原子操作的情况下,可以利用async函数组合出新的async函数。