zoukankan      html  css  js  c++  java
  • js异步原理与 Promise

    一、Javascript的异步原理

      javascript 是单线程语言,所以同一时间只执行一个运算。但有些方法是不能瞬间完成或不可预知何时完成的(如网络请求、settimeout等),为了让它们不对后续的运算产生阻塞,就需要用到异步操作。HTML5提出的Web Worker 允许在后台创建 JavaScript子线程,也可以用来防止阻塞,只是实现方对复杂、浏览器支持性不佳。

      javascript 的异步就是通过回调函数实现的。异步事件被触发时,即意味着对应的回调函数被执行。

      javascript 引擎会基于事件轮询(event-loop)机制捋出一个任务队列:执行所有的同步操作;过程中若遇到异步操作,就将异步事件排入另一个队列;待所有同步操作完成时,开始监听异步事件队列,等待事件触发并执行。

        setTimeout(function() {
            console.log("a");    
        }, 0); // 这里是异步,0延迟不代表立即执行
    
        var sum=0;
        for (var i = 0; i < 1000000; i++) {
            sum += i;
        };
        console.log("b" + sum);
    

      如上示例,会先打印出b,再打印a。

    二、Promise规范 

      Promise的目的是为了给异步编程提供统一接口,实现了回调函数的链式写法。目前Promise已经纳入了ES6标准,逐渐成为回调函数的写法规范。

    • 三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
    • 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态
    • promise必须实现then方法,并接受两个参数,分别是成功和失败后的回调

      Promise规范了Resolve、Reject、Then、Catch、All等方法。 Resolve和Reject分别指代异步操作执行成功和失败时对应执行的回掉函数,它们以参数的形式传入Then方法中。Catch用以捕获错误,All方法可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。ES6的Promise基本定义方法如下:

    var myPromise = new Promise(function(resolve, reject){
    	//做一些异步操作
    	setTimeout(function(){
    		console.log('执行完成');
    		resolve('数据传递');
    	}, 2000);
    });
    myPromise.then(function(data){
    	//数据处理代码...
    	console.log(data);
    });

      在创建myPromise的时候,向Promise构造函数传递了两个参数resolve和reject,此时这两个没有实际意义;在执行then的时候,才知道resolve具体是什么函数。上例的then只传了一个函数进来,默认为resolve;若传递了两个函数,则第二个即为reject。myPromise中定义了传给回调函数的数据,上例中“数据传递”即传给了resolve回调函数。

      写入Promise中的异步操作是会立即进入事件队列的,上例中,即使不写myPromise.then(),控制台依旧会打印出“执行完成”。在实际使用中,更科学的控制方式是将Promise对象的定义写入一个函数中,并return这个对象。

    function test(){
        var myPromise = new Promise(function(resolve, reject){
            setTimeout(function(){
                console.log('执行完成');
                resolve('数据传递');
            }, 2000);
        });
        return myPromise;            
    }
    test().then(function(data){
        console.log(data);
    });
    

      then的链式调用能够简化层层回调的写法,避免回调地狱。Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。在then的resolve方法中返回一个新的Promise对象或者一个数据,都可以后接新的then()。

    function test(){
      var promise1 = new Promise(function(resolve, reject){
        setTimeout(function(){
            console.log('第一个Promise执行完成');
            resolve('传递给第一个resolve的数据');
        }, 2000);
        });  
      return promise1;
    }
    test().then(function(val){
        console.log('进入第一个then');
        console.log(val);
        var promise2 = new Promise(function(resolve, reject){
          setTimeout(function(){
            console.log('第一个then执行完成');
            resolve('传递给第二个resolve的数据');
        }, 2000);  
        })
        return promise2;   //返回一个新的Promise对象
    }).then(function(val){
        console.log('进入第二个then');
        console.log(val);  
        return("传递给第三个resolve的数据")   //返回一个值,也可以接then(),其值将被当作参数传递给resolve
    }).then(function(val){
    	console.log("进入第三个then");
    	console.log(val);
    })
    

      

    三、Promise的执行优先级

    setTimeout(()=>{
    	console.log("setTimeout")
    },0)
    
    new Promise((resolve,reject)=>{
    	console.log("in promise")
    	resolve("promise resolve");
    }).then((data)=>{
    	console.log(data)
    })
    
    console.log("sync")
    

      上面代码的执行结果为:先后输出 in promise、sync、promise resolve、setTimeout

      首先要理解,Promise回掉函数的执行是异步的,但Promise本身的定义是同步执行的,所以按照顺序,in promise会在sync前输出。

      其次,Promise回调的优先级是高于setTimeout等异步操作的,所以promise resolve会先于seTtimeout输出。浏览器会将promise callbacks加入到同步事件队列的末尾,而不是异步事件的队列。

  • 相关阅读:
    井字棋先手必胜图解
    python 回溯法 子集树模板 系列 —— 19、野人与传教士问题
    pandas 索引与列相互转化
    按概率随机选取
    java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**
    java中文乱码解决之道(一)-----认识字符集
    Java提高篇(三八)-----Java集合细节(四):保持compareTo和equals同步
    Java提高配(三七)-----Java集合细节(三):subList的缺陷
    Java提高篇(三六)-----Java集合细节(二):asList的缺陷
    Java提高篇(三五)-----Java集合细节(一):请为集合指定初始容量
  • 原文地址:https://www.cnblogs.com/yangshifu/p/7198412.html
Copyright © 2011-2022 走看看