js 异步

110 阅读2分钟
  1. 为什么js使用单线程机制

    a. 避免复杂性。

    试想,如果是多线程,当一个线程正在操作某个dom节点的时候,
    另一个线程正试图删除该dom节点,浏览器应该如何判断操作
    

    b. HTML5 提出webworker

    允许创建多个线程,但子线程受主线程控制,并不可操作dom,本质并没有差异
    
  2. 同步 vs 异步

    a. 同步

     在主线程上执行的任务,必须前一个任务执行完毕,才能执行下一个任务
    

    b. 异步

     进入任务队列排队的任务。
     当异步任务完成,会在队列中添加一个事件【回调函数etc】,表明当前的异步任务可以进入执行栈。
     但是只有当执行栈中的所有同步任务完成,系统才会去读取任务队列
    
  3. js里的常见异步操作

    a. setTimeout / setInterval

     1.由浏览器内核的timer模块来处理,只有当时间到达的时候,才会将回调函数添加到任务队列中
     
     2.需等主线程的所有同步任务完成后才会执行,所以即使定时时间为0也不一定立马执行
    
        console.log(1);
        setTimeout(function(){console.log(2);},0);
        console.log(3);
        
        // 1,3,2
    

    b. ajax

     由浏览器内核的network模块来处理,在网络请求完成返回之后,才将回调添加至队列
    

    c. onClick 事件

     由浏览器内核的DOM Binding模块来处理,当事件触发的时候,回调函数立即添加至队列
    

    d. promise

     详见 -- 
    

    e. nodejs 的 process.nextTick

     在下一次Event Loop之前触发回调函数【主线程读取任务队列前】
     即在发生异步任务前
    
        process.nextTick(function A() {
        console.log(1);
        process.nextTick(function B(){console.log(2);});
        });
    
        setTimeout(function timeout() {
         console.log('TIMEOUT FIRED');
        }, 0)
        
        // 1
        // 2
        // TIMEOUT FIRED
        
        即使嵌套多个,都会在当前执行栈执行【指定的回调总在当前执行栈尾部触发】
    

    f. nodejs 的setImmediate

     在当前任务队列的尾部添加事件,在下一次Event Loop时执行
    
        setImmediate(function A() {
            console.log(1);
            setImmediate(function B(){console.log(2);});
        });
    
        setTimeout(function timeout() {
            console.log('TIMEOUT FIRED');
        }, 0);
        
        运行结果可能是1--TIMEOUT FIRED--2,也可能是TIMEOUT FIRED--1--2
        setImmediate 总是将事件注册到下一轮Event Loop
        
        将上述例子修改一下
        
        setImmediate(function (){
            setImmediate(function A() {
                console.log(1);
                setImmediate(function B(){console.log(2);});
        });
    
        setTimeout(function timeout() {
            console.log('TIMEOUT FIRED');
        }, 0);
        });
        
        // 1
        // TIMEOUT FIRED
        // 2
        // 运行结果是固定的,以内A和timeout是同一轮loop,二B已经是进入下一轮loop
        // 推荐使用setImmediate
    






参考 :

  1. 阮一峰 《JavaScript 运行机制详解:再谈Event Loop》