JavaScript是一门单线程非阻塞的脚本语言,单线程意味着,JavaScript代码在执行的任什么时候候,都只有一个主线程来处理全部的任务。而非阻塞则是当代码须要进行一项异步任务(没法马上返回结果,须要花必定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,而后在异步任务返回结果的时候再根据必定规则去执行相应的回调。
在乎识到该问题之际,html5新特性中的web worker可让JavaScript成为一门多线程语言,但实际开发中使用web worker存在着诸多限制。javascript
思考一下这段代码的结果?html
显然,同步函数是由上至下的执行顺序html5
由于setTimeout是异步函数,js执行机制是先将同步函数执行完毕,再执行异步函数java
当javascript代码执行的时候会将不一样的变量存于内存中的不一样位置:堆(heap)和栈(stack)中来加以区分。其中,堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针。以下:
当咱们调用一个方法的时候,js会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中存在着这个方法的私有做用域,上层做用域的指向,方法的参数,这个做用域中定义的变量以及这个做用域的this对象。 而当一系列方法被依次调用的时候,由于js是单线程的,同一时间只能执行一个方法,因而这些方法被排队在一个单独的地方。这个地方被称为执行栈。
当脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,而后从头开始执行。若是当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,而后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码所有执行完毕。web
在异步函数中,能够细分为两种任务,宏任务与微任务。
宏任务有如下几种:
①I/O
②setTimeout
③setInterval
④setImmediate
⑤requestAnimationFrame编程
微任务有如下几种:
①process.nextTick
②MutationObserver
③Promise.then catch finallypromise
当异步函数中同时存在微任务和宏任务的时候,先执行完微任务,再执行宏任务浏览器
浏览器中的事件循环机制就是js在执行代码时,由上至下遍历,优先执行同步函数,在遇到异步函数的时候,将该任务放置执行栈;当任务队列中没有同步函数以后便开始执行执行栈中的异步函数,优先执行微任务,后执行宏任务。
js执行顺序: 同步函数 -> 微任务 -> 宏任务多线程
console.log('script start') setTimeout(function(){ console.log('settimeout') }) console.log('script end') // 输出顺序:script start->script end->settimeout
这个很简单,setTimeout中的语句会进入宏任务,后置执行。异步
console.log('script start') let promise1 = new Promise(function (resolve) { console.log('promise1') resolve() console.log('promise1 end') }).then(function () { console.log('promise2') }) setTimeout(function(){ console.log('settimeout') }) console.log('script end') // 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
两个要点:
①promise中的then函数中代码会进入微任务
②promise中的resolve只是更改promise的状态,所以后面的语句会继续执行。
async function async1(){ console.log('async1 start'); await async2(); console.log('async1 end') } async function async2(){ console.log('async2') } console.log('script start'); async1(); console.log('script end') // 输出顺序:script start->async1 start->async2->script end->async1 end
async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会当即执行表达式,而后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行
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');
这题不公布答案,自行答题。