资讯专栏INFORMATION COLUMN

promise常见问题总结

caspar / 1281人阅读

摘要:常见问题总结如何中断的缺点之一就是无法让中断如上代码如何让的链式调用中断一种方法是在中直接抛错这样就不会执行直接跳到方法打印但此方法并没有实际中断另一种方法就是在中一个新的但不改变其状态这样该就一直处于状态即不会执行后面任何方法中断有啥用

promise常见问题总结 promise如何中断

promise的缺点之一就是无法让promise中断

Promise.resolve().then(() => {
    console.log("then 1")
}).then(() => {
    console.log("then 2")
}).then(() => {
    console.log("then 3")
}).catch((err) => {
    console.log(err)
})

如上代码如何让promise的链式调用中断?

一种方法是在then 1中直接抛错, 这样就不会执行then 2, then 3, 直接跳到catch方法打印err(但此方法并没有实际中断)

Promise.resolve().then(() => {
    console.log("then 1")
    throw new Error("xxx")
}).then(() => {
    console.log("then 2")
}).then(() => {
    console.log("then 3")
}).catch((err) => {
    console.log(err)
})

另一种方法就是在then 1中return 一个新的Promise,但不改变其状态,这样该Promise就一直处于pedding状态,即不会执行后面任何方法

Promise.resolve().then(() => {
    console.log("then 1")
    return new Promise(() => {})
}).then(() => {
    console.log("then 2")
}).then(() => {
    console.log("then 3")
}).catch((err) => {
    console.log(err)
})

中断有啥用? ---------- 可以让我想到超时中断问题

假设我们要用promsie自己封装一个ajax, 设置超时中断时间,如果没返回就不用返回了, 返回也不做处理了,不重要(虽然和上面的原理没关系,但不重要,上面是一个promsie的链式调用中断,此例是实际应用中的问题,你管我用几个promsie呢, 想到了记录一下)

function wrap(p1) {
    let abort
    let p2 = new Promise((resolve, reject) => {
        abort = reject
    })
    let p = Promise.race([p1, p2])
    // 将延时promise的reject方法挂在到p1与p2的race后的promise上, 可以在方法外通过调用p的cancel方法,来触发p2的reject
    p.cancel = abort
    return p
}

let fn = wrap(new Promise((resolve, reject) => {
    // 假设1秒后ajax返回, 调用resolve
    setTimeout(() => {
        resolve()
    }, 1000)
}))

fn.then(() => {
    console.log("ok")
}).catch(() => {
    console.log("err")
})

// 设置延时时间500ms, 如果500ms数据买回来,就中断
setTimeout(() => {
    fn.cancel()
}, 500)
promise 微任务的执行顺序

之前的promise中断好歹还可以强说有点用,下面这种例子,谁要是没事写在生产代码中,直接开除好吧~~~寻思寻思得了

const p = Promise.resolve();
;(()=>{
    const implicit_promise = new Promise(resolve =>{
        const promise = new Promise(resolve=>{
            resolve(p)
        }); 
        promise.then(()=>{ 
            console.log("after:await");
            resolve()
        })
    });
    return implicit_promise
})();
p.then(()=>{
    console.log("tick:a");
}).then(()=>{
    console.log("tick:b");
}).then(()=>{
    console.log("tick:c");
});

首先第一行生成一个resolve成功态的promise,然后自执行函数同步代码直接执行,
第5行resolve(p), 这里要知道resolve一个promsie要等到该promise执行then方法后才能拿到返回值
也就是说第7行的then要等到p的返回值拿到之后才执行
下面先把下面的链式编程拆一下

const p = Promise.resolve();
;(()=>{
    const implicit_promise = new Promise(resolve =>{
        const promise = new Promise(resolve=>{
            resolve(p)
        });
        promise.then(()=>{ 
            console.log("after:await");
            resolve()
        })
    });
    return implicit_promise
})();
let p1 = p.then(()=>{
    console.log("tick:a");
})
p1.then(()=>{
    console.log("tick:b");
}).then(()=>{
    console.log("tick:c");
});

自执行函数执行完,执行p1的回调先打印tick:a,且由于没有return值,所以默认return一个新的promise也就是p1接收的心promise
然后紧接着p1调用then方法,之后第7行也调用then方法, 所以相继打印tick:b和after:await
等到tick:b执行完返回一个新的promise,这才执行tick:c
所以打印顺序为 tick:a ==> tick:b ==> after:await ==> tick:c
这就是面向面试学习的精髓

async+await是怎么转化为promise的?
async function async1(){
    console.log("async1 start")
    await async2();
    console.log("async1 end")
}
async function async2(){
    console.log("async2")
}
console.log("script start")
setTimeout(function(){
    console.log("setTimeout") 
},0)  
async1();
new Promise(function(resolve){
    console.log("promise1")
    resolve();
}).then(function(){
    console.log("promise2")
})
console.log("script end");

这段代码在很多地方看到了,其他执行顺序很容易理解,唯一的问题就在于async1 end什么时候执行,我们先不考虑这行console
就很容易可以得到以下结果

// script start (同步代码,上面是两个函数还没有调用)
// async1 start (调用async1的时候执行async1函数,打印async1 start)
// async2 (在async1中调用async2, 打印async2)
// promsie1 (同步代码执行到new Promise, 在executor中执行同步代码, 打印promise1)
// script end (promise1 打印后暂不执行promsie2因为then回调是在微任务中,先执行同步代码, 打印script end)
// promise2 (同步代码执行完, 清空微任务)
// setTimeout (宏任务执行)

那么问题就在于async1 end什么时候执行

毫无疑问现在的问题在于await的原理,他肯定也是异步的微任务, 问题在于async1 end和promise2 谁先执行,
首先在node环境下测试是promise2先执行,但是在chrome中执行是async1 end先执行
由此可以得出await转化promise
在node中

async2().then(() => {
    console.log("async1 end")
})
// 你以为是这么转化的?我也是这么以为的,**但是**在node中的then函数中它默认用Promise又包裹一层所以是这样的
async2().then(() => {
    return Promise.resolve().then(() => {
        console.log("async1 end")
    })
})
// 有点恶心了~~~我测试的版本是v8.6.0以上版本
// 这样的执行顺序就是async1 end 在promise2之后
// script start
// async1 start
// async2
// promise1
// script end
// promise2
// async1 end
// setTimeout

但在chrome(74.0.3729.169)中的转化应该是只有一个then,then中直接调用console,所以在浏览器中就是

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

这个转化过程是通过结果推出来的,总之开发环境还是要避免这样的代码出现

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104934.html

相关文章

  • Promise学习总结

    摘要:引擎线程也称为内核,负责处理脚本程序例如引擎引擎线程负责解析脚本,运行代码。对象代表一个未完成但预计将来会完成的操作。注意一旦新建就会立即执行它属于,无法取消。 写在前面: 第一遍学Promise时, 只是大概过了一遍, 感觉学的不够深入, 这一篇算是对之前的一个总结吧. Promise在ES6中也属于一个较难理解的一部分; 所以在学习一个比较难理解的知识点时, 我们可以围绕这个知识点...

    twohappy 评论0 收藏0
  • 简要总结microtask和macrotask

    摘要:众所周知和都属于上述异步任务的一种那到底为什么和会有顺序之分这就是我想分析总结的问题所在了和的作用是为了让浏览器能够从内部获取的内容并确保执行栈能够顺序进行。只要执行栈没有其他在执行,在每个结束时,队列就会在回调后处理。 前言 我是在做前端面试题中看到了setTimeout和Promise的比较,然后第一次看到了microtask和macrotask的概念,在阅读了一些文章之后发现没有...

    yexiaobai 评论0 收藏0
  • javascript高级学习总结(二)

    摘要:那个率先改变的实例的返回值,就会传递给的回调函数。函数对函数的改进,体现在以下四点内置执行器。进一步说,函数完全可以看作多个异步操作,包装成的一个对象,而命令就是内部命令的语法糖。中的本质就是没有的隐藏的组件。 1、原型 - jquery使用showImg(https://segmentfault.com/img/bVbwNcY?w=692&h=442);注释 : 实例虽然不同,但是构...

    Songlcy 评论0 收藏0
  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • javascript异步编程总结

    摘要:以下总结了异步编程的种方式回调函数回调函数异步编程的最基本的方式。由小组的成员在规范中提出,目的是为异步编程提供统一接口。结尾参考文章异步编程参考文章使用详解 前言 Javascript语言的执行环境是单线程。 单线程: 一次只能完成一个任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。 单线程的好处是执行环境简单,坏处是在一些耗时的任务上会堵塞进程。比如读取一个...

    yearsj 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<