欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript从初级往高级走系列

程序员文章站 2022-05-02 16:33:37
异步 什么是单线程,和异步有什么关系 什么是event-loop 是否用过jquery的deferred promise的基本使用和原理 介绍一下async/await(和promise的区别、联系...

异步

什么是单线程,和异步有什么关系 什么是event-loop 是否用过jquery的deferred promise的基本使用和原理 介绍一下async/await(和promise的区别、联系) 异步解决方案

什么是单线程,和异步有什么关系

单线程-只有一个线程,只做一件事。js之所以是单线程,取决于它的实际使用,例如js不可能同添加一个dom和删除这个dom,所以它只能是单线程的。

console.log(1);

alert(1);

console.log(2);

上面这个例子中,当执行了alert(1),如果用户不点击确定按钮,console.log(2)是不会执行的。

为了利用多核cpu的计算能力,html5提出webworker标准,允许javascript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作dom。所以,这个新标准并没有改变javascript单线程的本质。

js异步

console.log(100);

settimeout(function(){

console.log(200);

},1000)

console.log(300);

console.log(400);

console.log(400);

.... // 这里来很多很多个console.log(400); 结果就是打印完所有的400,等一秒再打印200

event-loop

文字解释

事件轮询,js实现异步的具体解决方案 同步代码,直接执行 异步函数先放在异步队列中 待同步函数执行完毕,轮询执行 异步队列 的函数

上面那个例子的执行效果就是这样的:

实例分析:

这个例子中有两种情况,取决于ajax的返回时间,如果ajax时间小于100ms它就先放进异步队列

jquery deferred

jquery1.5前后的变化

var ajax = $.ajax({

url: 'data.json',

success: function(){

console.log('success1');

console.log('success2');

console.log('success3');

},

error: function(){

console.log('error');

}

})

console.log(ajax); // 返回一个xhr对象

// 链式操作

var ajax = $.ajax('data.json');

ajax.done(function(){

console.log('success1');

}).fail(function(){

console.log('error');

}).done(function(){

console.log()

})

console.log(ajax); // 返回一个deferred对象

无法改变js异步和单线程的本质 只能从写法上杜绝callback这种形式 它是一种语法糖形式,但是解耦了代码 很好的体现:开放封闭原则(对扩展开放,对修改封闭)

使用jquery deferred

// 给出一段非常简单的异步操作代码,使用settimeout函数

var wait = function(){

var task = function(){

console.log('执行完成)

}

settimeout(task, 2000);

}

wait();

新增需求:要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤

function waithandle(){

var dtd = $.deferred(); // 创建一个deferred对象

var wait = function(dtd){ // 要求传入一个deferred对象

var task = function(){

console.log('执行完成');

dtd.resolve(); // 表示异步任务已经完成

// dtd.reject(); // 表示异步任务失败或出错

}

settimeout(task, 2000);

return dtd; // 要求返回deferred对象

}

// 注意,这里一定要有返回值

return wait(dtd);

}

var w = waithandle();

w.then(function(){

console.log('ok 1');

}, function(){

console.log('err 1');

}).then(function(){

console.log('ok 2');

}, function(){

console.log('err 2');

})

当执行dtd.reject()时:

var w = waithandle();

w.then(function(){

console.log('ok 1');

}, function(){

console.log('err 1');

})

// 不能链式

w.then(function(){

console.log('ok 2');

}, function(){

console.log('err 2');

})

上面封装的waithandle方法,由于直接返回了dtd(deferred对象),所以用户可以直接调用w.reject()方法,导致无论是成功还是失败,最后都走失败。

// 修改

function waithandle(){

var dtd = $.deferred();

var wait = function(dtd){

var task = function(){

console.log('执行完成');

dtd.resolve();

}

settimeout(task, 2000);

return dtd.promise(); // 注意这里返回的是promise,而不是直接返回deferred对象

}

return wait(dtd);

}

es6的promise:点这里

// promise封装一个异步加载图片的方法

function loadimg(src) {

var promise = new promise(function(resolve,reject){

var img = document.createelement('img');

img.onload = function(){

resolve(img)

}

img.onerror = function(){

reject('图片加载失败')

}

img.src = src;

})

return promise;

}

async/await

这是es7提案中的,现在babel已经开始支持了,koa也是用async/await实现的。

then 只是将callback拆分了 async/await 是最直接的同步写法

// 伪代码

const load = async function(){

const result1 = await loadimg(src1);

console.log(result1);

const result2 = await loadimg(src2);

console.log(result2);

}

load();