Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 13 题:Promise 构造函数是同步执行还是异步执行,那么 then 方法呢? #19

Open
liiiku opened this issue Feb 22, 2019 · 41 comments
Labels

Comments

@liiiku
Copy link

liiiku commented Feb 22, 2019

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})

promise.then(() => {
  console.log(3)
})

console.log(4)

执行结果是:1243
promise构造函数是同步执行的,then方法是异步执行的

@kunish
Copy link

kunish commented Mar 7, 2019

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536

@LwDsmile
Copy link

学习了

@KaiOrange
Copy link

Promise new的时候会立即执行里面的代码 then是微任务 会在本次任务执行完的时候执行 setTimeout是宏任务 会在下次任务执行的时候执行

@pioneer26
Copy link

excutor执行器里面是同步执行的,then里面是异步操作

@yu910709
Copy link

yu910709 commented Apr 2, 2019

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536

请问为什么3在val之前?

@cliYao
Copy link

cliYao commented Apr 17, 2019

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536

请问为什么3在val之前?

3是在5后面打印出来的啊,第一轮事件循环的时候,microtask queue里面先添加的promise.resolve(5).then((val)=>{console.log(val)}),后添加的promise.then(() => {
console.log(3);
});

@yygmind yygmind changed the title 关于第13题的见解 第 13 题:Promise 构造函数是同步执行还是异步执行,那么 then 方法呢? Apr 26, 2019
@sunas
Copy link

sunas commented Jul 9, 2019

Promise必然是同步的。就then我补充一下:
在ES6时代有了微异步的设定,then作为最典型代表,算是异步的一员。
在ES5时代,实现then的方式则要看构造函数里resolve(或reject)的用法了,如果resolve被同步使用,实质上resolve仍然是同步的。

@wuzhong1030
Copy link

Promise 构造函数是同步执行,then 是异步执行。看一下 Promise 的实现就知道了。

@zhukunpenglinyutong
Copy link

看过 Event Loop 基础原理的就明白,Promise构造函数是同步执行,而 .then .catch .啥啥的是异步(还有process.nextTick等等,大家可以查),
而且放到了微队列中,async/await 中,await 前面的是同步,await 后面的是异步,写法上是这样,但是其实是 语法糖,最后还会转为 Promise.then的形式

@Hunterang
Copy link

.then()当然是同步执行,只不过是.then的cb被放入了微任务队列,产生了异步执行

@iamwelk
Copy link

iamwelk commented Jul 13, 2019

这个题和之前的第8题类似

@june38liu
Copy link

then()到底是同步执行还是异步执行?为什么回答里有的说是同步有的说是异步

@thinkfish
Copy link

then()到底是同步执行还是异步执行?为什么回答里有的说是同步有的说是异步

根据上面的回答,总结下应该是then函数本身是同步,then里面的cb是异步

@dyj7
Copy link

dyj7 commented Jul 23, 2019

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536
image

@liwfd
Copy link

liwfd commented Jul 26, 2019

image

@pekonchan
Copy link

只要好好理解下 Promise, 很多疑问会迎刃而解

抓重点理解Promise

@tiameg
Copy link

tiameg commented Aug 15, 2019

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536

请问在浏览器控制器中执行的时候,打印的3和6之间会有一个“随机数字”,它是怎么出现的,代表的什么呢?

@BajnHu
Copy link

BajnHu commented Aug 16, 2019

这里对上面的例子做一个扩展

常量 承诺 =   无极((决心,拒绝)=> {
   控制台。日志(1);
   解析(5);
   控制台。日志(2);
})。然后(VAL  => {
   控制台。日志(VAL);
};

承诺。然后(()=> {
   控制台。日志(3);
};

控制台。log(4);

的setTimeout(函数(){
   控制台。日志(6);
};

执行结果:124536

请问在浏览器控制器中执行的时候,打印的3和6之间会有一个“随机数字”,它是怎么出现的,代表的什么呢?

随机数字是seTimeout方法的返回值
setTimeout()方法的返回值是一个 **唯一的数值 **
如果你想要终止setTimeout()方法的执行,那就必须使用 clearTimeout()方法来终止,而使用这个方法的时候,系统必须知道你到底要终止的是哪一个setTimeout()方法(因为你可能同时调用了好几个 setTimeout()方法),这样clearTimeout()方法就需要一个参数,这个参数就是setTimeout()方法的返回值(数值),
用这个数值来唯一确定结束哪一个setTimeout()方法。

@HuangHuanHuan
Copy link

这里对上面的例子做一个扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

执行结果: 124536
resolve(5)也能调用到下面这个then方法吗
promise.then(() => {
console.log(3);
});

@fqw123
Copy link

fqw123 commented Sep 26, 2019

promise是微观任务,setTimeout是宏观任务,先执行微观任务,在执行宏观任务;微观任务里,先执行同步再执行异步 所以结果是 124536

@Longgererer
Copy link

promise构造函数肯定是同步执行的,new Promise和其他的什么new Map、new Set一样的都是同步执行,当执行resolve方法将promise状态更新为fulfilled,并返回一个promise对象,调用then就会将then中的回调放入微任务队列中,也就是说promise.then才是异步

@huaipomen
Copy link

严格来说 构造函数 then都是同步的, 只是then内部的这个参数回调函数需要看resolve执行时机 并且内部做了个定时器, 所以回调才是异步的

@pigPEQ
Copy link

pigPEQ commented Nov 12, 2019

整体代码、setTimeout、setInterval、Promise构造函数是宏任务,promise的then方法是微任务

@ftchan
Copy link

ftchan commented Nov 15, 2019

假如有这么一段代码

new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2));
    Promise.resolve().then(() => console.log(5));
}).then(t => console.log(t));

请问为什么输出结果是2,5,1呢?
resolve(1) 之后,不应该是优先注册了外部 .then 的回调吗?
还是说内部的 Promise 是同步执行的?

@Longgererer
Copy link

应该

假如有这么一段代码

new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2));
    Promise.resolve().then(() => console.log(5));
}).then(t => console.log(t));

请问为什么输出结果是2,5,1呢?
resolve(1) 之后,不应该是优先注册了外部 .then 的回调吗?
还是说内部的 Promise 是同步执行的?

当然是异步啦,在执行resolve()之前会先将其他语句执行完的

@tangdou369098655
Copy link

Promise对象,就是将异步操作以同步操作的流程表达出来

@yygmind yygmind added the 异步 label Dec 16, 2019
@lusq010
Copy link

lusq010 commented Apr 18, 2020

我的天。then当然也是同步执行,then方法的参数callback函数才会在then等待状态变化的promise fulfill或者reject后起一个微任务把callback丢进去

@ggzcg
Copy link

ggzcg commented Jun 1, 2020

这题还不如直接问Promise的原理或写法

@fengmiaosen
Copy link

.then()当然是同步执行,只不过是.then的cb被放入了微任务队列,产生了异步执行

更详细一点的说法是等到 promise变为 resolved状态的时候,then注册的回调函数才被放入到微任务队列中,等待调用执行

@slogeor
Copy link

slogeor commented Jul 12, 2020

.then()当然是同步执行,只不过是.then的cb被放入了微任务队列,产生了异步执行

更详细一点的说法是等到 promise变为 resolved状态的时候,then注册的回调函数才被放入到微任务队列中,等待调用执行

promise = new Promise((resolve, reject) => {
    console.log(1);
    setTimeout(() => {
        resolve(5);
    }, 10)
    console.log(2);
  }).then(val => {
    console.log(val);
  });
  
  promise.then(() => {
    console.log(3);
  });
  
  console.log(4);
  
  setTimeout(function() {
    console.log(6);
  });

补段代码

@tjwyz
Copy link

tjwyz commented Jul 16, 2020

做戏做全套... 写一个更有助于理解

ps: 微任务以宏任务(setTimeout)替代

class PromiseA {
    constructor(fn) {
        this.status = 'pending';
        this.value = null;
        this.error = null;

        this.resolveArr = [];
        this.rejectArr = [];

        let resolve = (value) => {
            // 防止多次resolve
            if (this.status !== 'pending') return;
            setTimeout(()=>{
                this.value = value;
                this.status = 'fullfiled';
                // 派发过往订阅
                while(this.resolveArr.length) {
                    let tmp = this.resolveArr.shift();
                    tmp(value);
                }
            }, 0);
        }
        let reject = (err) => {
            // 防止多次reject
            if (this.status !== 'pending') return;
            setTimeout(()=>{
                this.status = 'rejected';
                this.error = err;
                // 派发过往订阅
                while(this.rejectArr.length) {
                    let tmp = this.rejectArr.shift();
                    tmp(err);
                }
            }, 0);
        }
        fn(resolve, reject);
    }
    then(fun1, fun2) {
        // 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
        (typeof fun1 !== 'function') && (fun1 = value => value)
        // 
        (typeof fun2 !== 'function') && (fun2 = error => {
            throw(error);
        })

        return new PromiseA((resolve, reject)=>{
            let resolveItem = (param) => {
                try {
                    let tmp = fun1(param);
                    tmp instanceof PromiseA ? tmp.then(resolve, reject) : resolve(tmp);
                } catch (e) {
                    reject(e);
                }
            }
            let rejectItem = (err) => {
                try {
                    let tmp = fun2(err);
                    tmp instanceof PromiseA ? tmp.then(resolve, reject) : resolve(tmp);
                } catch (e) {
                    reject(e);
                }
            }

            if (this.status == 'pending') {
                this.resolveArr.push(resolveItem);
                this.rejectArr.push(rejectItem);
            } else if (this.status == 'fullfiled') {
                resolveItem(this.value);
            } else if (this.status == 'rejected') {
                rejectItem(this.error);
            }
        });
    }
    catch(rejectFn) {
        return this.then(null, rejectFn);
    }
    finally(fn) {
        // 保证了fn执行在前.. 但是有点绕
        return this.then((param)=>{
            // 万一 fn reject了
            return PromiseA.resolve(fn()).then(()=>param, ()=>param);
        }, (err) =>{
            // 万一 fn reject了
            return PromiseA.resolve(fn()).then(()=>{
                throw err;
            }, ()=>{
                throw err;
            });
        })
    }
    static resolve(param) {
        if (param instanceof PromiseA) return param;
        return new PromiseA((resolve)=>{
            resolve(param);
        })
    }
    static reject(param) {
        if (param instanceof PromiseA) return param;
        return new PromiseA((resolve, reject)=>{
            reject(param);
        })
    }

    static all(arr) {
        return new PromiseA((resolve, reject)=>{
            let i = 0;
            let ret = [];
            while(arr.length) {
                let tmp = arr.shift();
                tmp.then((param)=>{
                    ret[i] = param;
                    i++
                    if (i == arr.length) {
                        resolve(ret);
                    }
                },(err) => {
                    reject(err);
                })
            }
        });
    }
    static race(arr) {
        // 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
        return new PromiseA((resolve, reject) => {
            arr.forEach((item)=>{
                // 状态变化是单向的
                item.then(resolve, reject);
            })
        })
    }
    // 允许reject X次 失败后Y秒继续触发
    static retry(fn, x, y) {
        return PromiseA((resolve, reject)=>{
            let failTimes = 0;
            // 也可以把历代err保存起来
            // let errArr = [];

            function cb () {
                fn().then(resolve).catch((err)=>{
                    if (failTimes == x) {
                        reject(err);
                        return;
                    }

                    setTimeout(()=> {
                        cb();
                    }, y);

                    failTimes++;
                });
            }
            cb();
        }) 
    }

    static promisefy (cb) {
        return (...arg)=>{
            return new Promise((reoslve, reject)=>{
                cb(...arg, reoslve);
            })
        }
    }
}

@MrLeihe
Copy link

MrLeihe commented Apr 14, 2021

promise 的构造函数是同步执行的,then方法也是同步执行的,只不过 then 里面的回调函数是异步执行的。

@TenviLi
Copy link

TenviLi commented Apr 26, 2021

⚠ 同志们,这道题绝对没有你们想象的这么简单,补充一个不错的文章中的摘录:

在Promises/A+规范的Notes 3.1中提及了promise的then方法可以采用“宏任务(macro-task)”机制或者“微任务(micro-task)”机制来实现。所以开头提及的promise在不同浏览器的差异正源于此,有的浏览器将then放入了macro-task队列,有的放入了micro-task 队列。在jake的博文Tasks, microtasks, queues and schedules中提及了一个讨论vague mailing list discussions,一个普遍的共识是promises属于microtasks队列。

—— https://segmentfault.com/a/1190000038985579

@leeFengHuo
Copy link

const promise = new Promise(async (resolve, reject) => {
console.log(1)
await resolve()
console.log(2)
})

promise.then(() => {
console.log(3)
})

console.log(4);
碰到过这种扩展,想了解为什么2在3之前执行

@Chorer
Copy link

Chorer commented Aug 6, 2021

const promise = new Promise(async (resolve, reject) => {
console.log(1)
await resolve()
console.log(2)
})

promise.then(() => {
console.log(3)
})

console.log(4);
碰到过这种扩展,想了解为什么2在3之前执行

这种出现 await 的代码,你可以等价转化为:

const promise = new Promise(async (resolve, reject) => {
   console.log(1)
   Promise.resolve(resolve()).then(() => {
       console.log(2)
   })
})
promise.then(() => {
   console.log(3)
})

console.log(4);

也就是将 await 后面跟着的部分用一个 Promise.resolve() 包裹起来,然后剩余部分塞到一个 then 的回调函数里。这样再分析就简单了。

@gromy92
Copy link

gromy92 commented Mar 4, 2022

严格来说then方法 是同步执行的,then方法的参数(回调函数)是 异步执行的

@xuchao996
Copy link

excutor执行器里面是同步执行的,then里面是异步操作

如何体现呢?能举例说明吗?

@yumengbdw
Copy link

之所以then是异步是为了处理循环引用的问题。

const p1 = promise1.then(value => {
    return p1
})

判断then里面new的promise 跟successCallback执行后得到的p1是不是同一个promise。
但是then里面处理回调的时候new的promise还没有创建完成。

@Yuweiai
Copy link

Yuweiai commented Jul 4, 2022

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})

promise.then(() => {
  console.log(3)
})

console.log(4)

执行结果是:1243 promise构造函数是同步执行的,then方法是异步执行的

【resolve对比await】这里虽然有resolve,但会打印同时先后打印1/2,如果是await,会先执行await后面的表达式,然后将其后的代码加入到微任务队列

@WangYunFei1
Copy link

promise是同步执行的,then也是同步的,只是then中的回调时异步执行的

@Yangfan2016
Copy link

可以看 promise的 实现

resolve 回调里的内容 会放入 微任务中
then 的回调只是一个list push 动作,
等 resolve 里的 微任务 执行完,就会 调用 then 里的 回调

so 构造器里除了 resolve 之外的 都是 同步执行的(await resolve() 这种情况除外)
then 里的回调是异步执行的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests