关于js的同步任务和异步任务

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

JavaScript的执行环境如浏览器或者nodejs都是以单线程作为主线程来运行的。单线程,就是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,意思就是js的执行上下文一次只能完成一项任务,这个任务执行完后才能执行下一个,它会阻塞其他任务,这就是主线程。

同步

同步运行,同步任务是存储在栈上的,每次会同步清楚每个同步任务,一次只能运行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务,这样就会导致线程阻塞

异步

异步模式,即与同步模式相反,异步任务是以队列的形式来储存的,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果前一个人物需要等待,可先执行后面的任务,等到前置任务结果返回后再继续回调 例:

setTimeout(function() {
    console.log('1');
}, 0);
setTimeout(function() {
    console.log('3');
}, 0);
console.log('2');
复制代码
2
1
3
复制代码

上面的代码输出顺序为2,1,3。即在事件循环中首先会录入所有的同步任务依次执行,执行完所有的同步任务之后才会执行异步任务。

回调函数

回调函数被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。

function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('name');
  callback(name);
}

processUserInput(greeting);
复制代码

然而需要注意的是,回调函数经常被用于继续执行一个异步 完成后的操作,它们被称为异步回调。 同步回调依然会阻塞代码的执行,而异步回调如setTimeout的回调函数就会等待同步任务执行完后才会执行。 由于通常的业务中会使用到多个异步回调进行数据获取或者处理。这样为了等待异步任务的执行完毕,我们需要在异步任务的回调函数中进行下一步操作,如果要处理多个异步回调事件,就会形成一个个回调函数的嵌套,代码一多,就很不方便阅读与开发。如:

function load() {
    $.ajax({
        url: 'xxx.com',
        data: '123',
        success: function(res) {
            init(res, function(res) {
                render(res, function(res) {
                    //...
                });
            });
        }
    }
}

load();
复制代码

于是就有Generator的出现以及ES6Promise的出现,来解决这种问题,Generator在其他语言中早就有了,它的作用是暂停函数的执行,通过yield来控制函数的执行,从而实现异步管理功能,但是由于写法比较复杂,一直没有得到广泛使用。直到Promise的出现,首次提出了Pendingfullfilledrejected三种状态来管理函数的执行,更方便的管理我们的代码。在之后的es7中根据promise的使用,又提出了async以及await语法糖,实际是Generator的语法糖,通过它们我们可以以同步的书写方式,来得到异步代码调用的效果。具体原理由下一篇文章分析。

分类:
前端
标签: