setTimeout(function(){})堆栈ES6 Promise

    xiaoxiao2021-04-16  33

    /* *SetTimeout()的用法 *回调函数 */

    var learingSetOneTime = null; var learingSetSecondTime = null; function learningSetTimeout(){ console.log(a); learingSetOneTime = setTimeout(function(){ console.log(a); },0); learingSetSecondTime = setTimeout(function(){ console.log(a); },1000); var a = 2; }

    输出结果:undefined 2 2

    还是那句话 同步 异步 回调

    /* *在这讨论下之前在知乎看到的 80% 应聘者都不及格的 JS 面试题setTimeout *因为涉及到我还比较感兴趣的ES6,所以我也来谈一谈 */

    function showSetResult(){ for(var i = 0; i < 5; i++){ setTimeout(function(){ console.log(i); },1000); } } showSetResult(); //输出结果:在这里提个建议:凡是看到代码,在情况允许的条件下还是在电脑上跑一下比较好,自己看下结果 == > 隔1秒一次性输出5个5;

    至于原因还是那句话:回调函数; /* *回调函数的执行:这里涉及到javascript单线程如何处理回调的? * *javascript的同步代码在JavaScript同步的代码是在堆栈中顺序执行的,而setTimeout回调会先放到消息队列,for循环每执行一次,就会放一个setTimeout到消息队列排队等候,当同步的代码执行完了,再去调用消息队列的回调方法。i是showSetResult()函数的局部变量,没有记忆的过程,所以当同步函数执行完了之后for循环已经完成了,此时i的值为5. */

    这里提到了堆栈的问题: 就简单提一下堆栈的问题: 什么是栈?存储原始数据类型和引用数据类型的实体的起始地址 原始数据类型:undefined、null、string、number、boolean,存储在栈(stack)中的简单段,占用空间小,大小固定,属于被频繁属于数据 什么是堆:存储引用类型实体 引用类型:Array、Object、function,占用空间大,大小不固定。通过起始地址的指针访问实体数据位置 当解析时,会先检索其再栈中的地址,取得地址之后再从堆中获取实体数据

    /* *进一步改进,输出0,1,2,3,4 *在javascript中没有块级作用域的问题(ES6有),通过立即执行函数可以实现块级作用域 */

    function showSetResult(){ for(var i = 0; i < 5; i++){ (function(i){ setTimeout(function(){ console.log(i); },1000); }(i)) } } showSetResult();

    /* *立即执行函数:最外层的大括号是将括号里的函数作为函数表达式来解析,将i作为参数传给立即执行函数。相当于将i做了记忆,此时是隔一秒一次性输出0,1,2,3,4,我如果想要每隔一秒输出一个呢? */

    function showSetResult(){ for(var i = 0; i < 5; i++){ (function(i){ setTimeout(function(){ console.log(i); },1000 * i); }(i)) } } showSetResult();

    /* *此时输出就是每个一秒输出1个 数,0,1,2,3,4 */

    那ES6是怎么解决的呢?

    上边提到了块级作用域:ES6的let定义的就是用来解决这个问题的

    let:声明的变量只在块级作用域中有效 const:声明一个常量,一旦声明,常量的值就不能改变,只有在声明所在的块级作用域中有效 使用let声明的变量就不存在变量提升的问题了,在该变量声明之前,该变量是不可用的。

    function showSetResult(){ for(let i = 0; i < 5; i++){ setTimeout(function(){ console.log(i); },1000 * i); } } showSetResult();

    /* *此时你可以运行看看,结果是Error */ 这就是let,let的作用域是当前块。也就是for循环。在for中声明的let在setTimeout中是不可用的。在这里let本身就形成了一个闭包。外部是不能访问的。

    其实这个就相当于:

    function showSetResult(){ for(var i = 0; i < 5; i++){ showI(i); } } function showI(i){ setTimeout(function(){ console.log(i); },1000 * i); } showSetResult();

    所以说:let其实就是个语法糖,那使用ES6怎么完成呢?

    怎么改呢?

    const tasks = []; (function(j){ tasks.push(new Promise(function(resolve,reject){ setTimeout(function(){ console.log(j); resolve(); //调用resove,不调用的话就不会异步调用到then }, 1000 * j); })); }(i)) Promise.all(tasks).then(function(){ setTimeout(function(){ console.log(i); }, 1000); // 注意这里只需要把超时设置为 1 秒 }); /* *promise.all(); *参数数组的顺序一致,而不是按时间顺序排序 *如果数组中所有的Promise对象都resolve了,那么这些resolve的值将作为一个数组作为Promise.all这个方法的返回值的(Promise对象)的resolve值,之后可以被then方法处理。如果数组中任意的Promise被reject,那么该reject的值就是Promise.all方法的返回值的reject值. *Promise.race() *不是等待所有的promise被resolve或reject,而是所有的promise中只要有一个执行结束,它就会触发 */

    promises的真正强大之处在于多重的链接 == > 特性: 1)只有来自上一层的异常可以被捕捉 2)错误可以被恢复 == > 在一个错误回调函数中,如果你不重新抛出错误,promise会假设你已经从错误中恢复,并且反转成为已解决状态 3)Promises可以被暂停 4)Resolved Promises并不会立刻执行

    两种情形: 1)假设传入的参数没有一个.then方法,那么这个返回的Promise对象变成了resolve状态,其resolve的值就是这个对象本身。 2)假设传入的参数带有一个then方法(称为thenable对象), 那么将这个对象的类型变为Promise,其then方法变成Promise.prototype.then方法。

    转载请注明原文地址: https://ju.6miu.com/read-672887.html

    最新回复(0)