浅谈JS异步(asychrouous)

一、概念

(1)asychronous 异步
是JS这种单线程语言解决多任务的一种方法,将耗时的任务(io)设定为异步工作,先交给浏览器负责相关功能的线程来实现耗时的部分工作,按顺序放入任务队列中,等待主代码执行完成,而主线程继续下一个任务,不阻塞代码;主线程任务完成后,会收到浏览器的通知,来实现异步任务的其他代码执行
===>事件循环+任务队列

(2)sychronous 同步

任务的执行是一个接着一个执行的,上一个任务执行完成才能继续下一个任务,有多个窗口,进行一个接一个的执行任务

二、异步有序问题

1、回调=====>回调地狱

当我们需要进行有序任务时,最粗暴的方式就是用时间函数嵌套,少个还可以分辨,但若出现上百、上千个事件呢?如果任然使用这种方法,就会形成“回调地狱”,没有办法阅读处时间函数的时间对应的代码是哪一个:

setTimeout(function () {
            console.log("a");
            setTimeout(function () {
                console.log("b");
                setTimeout(function () {
                    console.log("c");
                    setTimeout(function () {
                        console.log("d");
                    }, 1000)
                }, 2000)
            }, 1000)
        }, 1000)

于是乎,我们的先人们捣鼓出了专门处理异步的方法。

2、Promise 承诺

首先,我们来看一看Promise 与上面的代码有什么不同

        new Promise(function (resolve, reject) {
            // console.log("a1");
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 1000)
        }).then(() => {
            // return 1;//下一个then被处罚时可以接收返回值

            return new Promise(function (resolve, reject) {
                // console.log("b1");
                setTimeout(function () {
                    console.log("b");
                    resolve();
                }, 2000)
            })
        }).then((data) => {
            return new Promise(function (resolve, reject) {
                // console.log("c1");
                setTimeout(function () {
                    console.log("c",data);
                    resolve();
                },3000)
            })
        })

我们可以看到,Promise让每一个异步都是平行的了,不再是嵌套关系,语义化非常强,让人一眼可以看出每个事件发生的顺序。

(1)使用Promise要注意状态值:

  • pending   已就绪 Promise实例化的同时就已就绪,状态只可改变1次,且不可逆
  • resolved/fulfilled   已完成
  • rejected   已失败

===>状态改变,then方法会触发onfulfilled,onrejected事件

(2)Promise方法

我们分步骤来看,是怎样应用的:

new Promise(function(resolve,reject){});

//两个形参:resolve reject ,都是回调函数

 let fn1;
 let fn2;
new Promise(function(resolve,reject){//两个形参,都是回调函数
       resolve();
       fn1 = resolve;
       fn2 = reject;
});            

resolve()方法会返回已完成状态,就会触发onfulfilled事件,让then()代码走下去

若要写异步函数,则将第一个异步函数卸写在在Promise里面,then()让后面的函数继续走

 p.then((data)=>{//参数为2个事件监听器,第一个是已成功时触发,第二个是以失败时触发
        console.log("onfulfilled",data);
},(data)=>{
         console.log("onrejected",data);//onrejected 触发且异常,不报错
  })

 console.log(p);

then :

  • 返回值为promise对象,初始状态是pending
  • 监听器被触发,监听函数执行完成后,返回值的状态发生改变
  • 改变的情况由监听函数的执行返回值决定,而具体情况参照Promise.resolve(返回值)

then(onfulfilled,onrejected)含有两个参数,都是事件监听器(函数),第一个是已成功时触发,第二个是以失败时触发。onrejected 触发且异常时,不报错。

整体的代码就是:

 let fn1;
            let fn2;
        let p = new Promise(function(resolve,reject){//两个形参,都是回调函数
            resolve();
            //第一个异步函数放在Promise里
            fn1 = resolve;
            fn2 = reject;
        });

        p.then((data)=>{//参数为2个事件监听器,第一个是已成功时触发,第二个是以失败时触发
            console.log("onfulfilled",data);

        },(data)=>{
            console.log("onrejected",data);//onrejected 触发且异常,不报错
        })

        console.log(p);

(3)all(),race()

在Promise中有两个好用的方法,就是 all(),race()

  • all()方法:在所有异步代码都跑了后,同时输出结果,但结果显示顺序根据异步事件结束的先后来的
     let p1 = new Promise(function (resolve, reject) {
            console.log("a开始了");

            setTimeout(function () {
                console.log("a");
                resolve();
            }, 4000)
        })
        let p2 = new Promise(function (resolve, reject) {
            console.log("b开始了");
            setTimeout(function () {
                console.log("b");
                resolve();
            }, 3500)
        })
        let p3 = new Promise(function (resolve, reject) {
            console.log("c开始了");
            setTimeout(function () {
                console.log("c");
                resolve();
            }, 5000)
        })

        let pp = Promise.all([p1,p2,p3]);
        pp.then(()=>{
            console.log("all");

        })

  • race()方法:赛跑,谁先结束谁先输出
        let p1 = new Promise(function (resolve, reject) {
            console.log("a开始了");

            setTimeout(function () {
                console.log("a");
                resolve();
            }, 4000)
        })
        let p2 = new Promise(function (resolve, reject) {
            console.log("b开始了");
            setTimeout(function () {
                console.log("b");
                resolve();
            }, 3500)
        })
        let p3 = new Promise(function (resolve, reject) {
            console.log("c开始了");
            setTimeout(function () {
                console.log("c");
                resolve();
            }, 5000)
        })

        // let pp = Promise.all([p1,p2,p3]);
        // pp.then(()=>{
        //     console.log("all");

        // })

        pp = Promise.race([p1,p2,p3]);
        pp.then(()=>{
            console.log("race");

        })

b时间最短,因此是b获胜

all、race 都生成promise对象,但是状态的变化情况不一样

(4)返回值 return

Promise.value 通过resolve传递的参数

Promise.reslove(value)方法,返回一个以给定值解析后的Promise对象
value有三种情况:

  1. 普通值:除了promise对象,和thenable对象的所有值,生成一个已完成的promise对象并且PromiseValue的值就是传入的value
  2. promise对象,直接返回该value
  3. thenable对象,参照new Promise 生成的promise对象,其中then方法就好比new Promise(cb)中的cb

在then(data)中,data就是value的值,我们回到开头的那段代码:

new Promise(function (resolve, reject) {
            // console.log("a1");
            setTimeout(function () {
                console.log("a");
                resolve();
            }, 1000)
        }).then(() => {
            // return 1;//下一个then被处罚时可以接收返回值

            return new Promise(function (resolve, reject) {
                // console.log("b1");
                setTimeout(function () {
                    console.log("b");
                    resolve();
                }, 2000)
            })
        }).then((data) => {
            return new Promise(function (resolve, reject) {
                // console.log("c1");
                setTimeout(function () {
                    console.log("c",data);
                    resolve();
                },3000)
            })
        })
then(() => {
            // return 1;//下一个then被处罚时可以接收返回值,大家可以自己去试一试。

原文地址:https://www.cnblogs.com/yuanjunjundebo/p/12045998.html

时间: 2025-02-01 17:47:38

浅谈JS异步(asychrouous)的相关文章

浅谈JS之AJAX

0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HTTP和web服务器进行数据交换(用户不知道也感觉不出来,就跟桌面应用程序似的进行数据交互),它不会导致页面重新加载,这样才有更好的用户体验. Ajax是基于以下开放标准: javascript(DOM) css html xml(json) 通俗的说就是使用了javascript(DOM)的XMLH

浅谈 js eval作用域

就简单聊下如何全局 eval 一个代码. var x = 1; (function () { eval('var x = 123;'); })(); console.log(x); 这个代码得到的是 1 而不是 123如果想让 eval 执行的代码是全局的,那么有几种方法. var x = 1; (function () { window.eval('var x = 123;'); })(); console.log(x); 这个方法标准浏览器都可以得到 123 而IE6-8则依然是 1 相同的

浅谈 js 正则之 test 方法

原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. ? 1 2 3 4 5 var re = /\d/; console.log( re.test("1") ); console.log( re.test("1") ); console.log( re.test("1") ); console.log( re.test("1"

浅谈 js 语句块与标签

原文:浅谈 js 语句块与标签 语句块是什么?其实就是用 {} 包裹的一些js代码而已,当然语句块不能独立作用域.可以详细参见这里<MDN block> 也许很多人第一印象 {} 不是对象字面量么?怎么成了语句块了?如果在赋值语句或者表达式里用的时候,确实是对象字面量,如: var a = {}; ({toString:function(){return "hehe"}}) + "..."; 是不是很有意思..但是直接使用如: {toString: fu

浅谈 js 下 with 对性能的影响

这几天多次看到有博主们在写 with 的文章,这货确实非常方便,但是却是个性能杀手,所以一直都是上不得台面的.那么他究竟会让效率低下到什么程度呢?先来看下 with 是如何的便捷吧.. // 正常调用 console.log(location.host); console.log(location.pathname); // 在 with 下 with (location) { console.log(host); console.log(pathname); } 如果不影响性能,确实是非常霸气

浅谈 js 数字格式类型

原文:浅谈 js 数字格式类型 很多人也许只知道 123,123.456,0xff 之类的数字格式.其实 js 格式还有很多数字格式类型,比如 1., .1 这样的,也有 .1e2 这样的. 可能有人说这是什么个格式?其实还不止呢.1          //11.2       //1.21.2e3    //12001.2e+3  //12001.2e-3  //0.0012.12e+2 //12-.12e-2 //-0.0012 当然这些只是十进制.我们来说说 八进制 和 十六进制.0x00

浅谈 js 字符串 trim 方法之正则篇

position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流

从window.console&amp;&amp;console.log(123)浅谈JS的且运算逻辑(&amp;&amp;)

从window.console&&console.log(123)浅谈JS的且运算逻辑(&&) 作者:www.cnblogs.com  来源:www.cnblogs.com  发布日期:2015-03-01 一.JS的且运算记得最开始看到window.console&&console.log(123),当时知道能起什么作用但是没有深入研究,最近在研究后总算弄明白了.要理解这个,首先得明白三个知识点第一:短路原则这个大家都非常清楚的了,在做且运算的时候,“同真

浅谈 js 对象 toJSON 方法

前些天在<浅谈 JSON.stringify 方法>说了他的正确使用姿势,今天来说下 toJSON 方法吧.其实我觉得这货跟 toString 一个道理,他是给 stringify 方法字符串化的时候调用的.看下 MDN 官方文档吧<toJSON behavior>.非常简单,但是要注意的是他和 stringify 方法第二个参数稍微有点不同.因为 stringify 第二个参数是回调函数时,只是对当前 key 对应的值进行修改.而 toJSON 则是对当前对象进行修改.例如: v