Coder Social home page Coder Social logo

Comments (30)

lfpdev avatar lfpdev commented on May 22, 2024 3

ES6 在 Promise/A+ 规范基础上扩展了一些功能,例如:resolve 解析 promise 和 thenable 对象,根据一些测试用例做了补充和修改(node环境),感兴趣可以参考 https://github.com/lfpdev/promise

from blog.

ljianshu avatar ljianshu commented on May 22, 2024 1

大佬真棒!学习的榜样!

from blog.

liuzhilei avatar liuzhilei commented on May 22, 2024

棒棒哒

from blog.

guangyuan-T avatar guangyuan-T commented on May 22, 2024

顶礼膜拜,看多了都是泪😭

from blog.

pengpeng9413 avatar pengpeng9413 commented on May 22, 2024

小姐姐棒棒的,今天看了你的这篇promise,自己试着写了一遍

from blog.

pengpeng9413 avatar pengpeng9413 commented on May 22, 2024

小姐姐棒棒的,今天看了你的这篇promise,自己试着写了一遍

from blog.

panzhang5 avatar panzhang5 commented on May 22, 2024

看小姐姐的文章能找到好工作

from blog.

yifan-blog avatar yifan-blog commented on May 22, 2024

good

from blog.

biubiupiu1 avatar biubiupiu1 commented on May 22, 2024
let x = new Promise((resolve, reject) => {
  resolve(
    new Promise((resolve, reject) => {
      resolve(2);
    })
  );
}).then(res => {
  console.log(res);
});

我发现一个问题就是,这个在浏览器的Promise中,和这里实现的Promise是不一致的,想问下这是新规范吗

from blog.

c-wchen avatar c-wchen commented on May 22, 2024

resolvePromise中self是多余的,好几次以为是自身对象,debug走一遍之后发现是window,再往下面看的时候发现并没有用到。

from blog.

nosillytrying avatar nosillytrying commented on May 22, 2024
let x = new Promise((resolve, reject) => {
  resolve(
    new Promise((resolve, reject) => {
      resolve(2);
    })
  );
}).then(res => {
  console.log(res);
});

我发现一个问题就是,这个在浏览器的Promise中,和这里实现的Promise是不一致的,想问下这是新规范吗

// 1) Promise 是一个类或者一个方法
// 2) Promise 有三种状态 pending (等待态) fulfilled (成功态) rejected (失败态)
// 默认为pending态
// 只有是pending态的时候才能更改状态为fulfilled 或者 rejected 状态一旦更改就不允许再次被修改
// 3) Promise 内部提供一个成功的value, 一个失败的reason
// 4) Promise 内部提供两个方法 一个resolve 一个reject
// 如果两个方法都不传 默认返回undefined
// resolve或者reject不能抛异常 代码会直接报错
// resolve接收成功的value reject接收失败的reason
// 调用resolve 会把状态从 pending 更改为 fulfilled
// 调用reject 会把状态从 pending 更改为 rejected
// 如果在executor 执行器中异步调用resolve或者reject 例如setTimeout调用
// 如果在异步任务重抛出异常 则会直接执行这个throw抛出的 不会走入到下面的then方法的回调了
// then回调时候状态依然是pending态 需要发布订阅模式处理 将订阅的存放在数组里面
// 为什么存放的是一个数组呢 应为一个实例 可以then多次 一个多次订阅
// 成功的onFulfilledCallBacks 失败的onRejectedCallBacks
// 5) Promise 接收一个 executor 执行器, 默认会立即执行
// 第一个参数就是内部提供的resolve 第二个参数就是内部提供的参数reject
// 多个resolve跟reject嵌套的话 应该以最后一个的作为结果
// 6) Promise 有个then函数 默认有两个参数onFulfilled 和 onRejected
// onFulfilled resolve或者reject调用之后返回的是一个普通值或者一个新的promise调用的resolve的值
// 将value作为参数传递给onFulfilled
//
// onRejected resolve和reject调用之后的回调返回一个promise的reject的值或者抛出异常 将reason作为参数传递给onRejected

// then有返回值

// catch的特点是 如果都没有错误处理 一层层找 没有找到错误处理 会找最近的catch catch也是then

// promise中实现链式调用 返回一个新的promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 判断x的状态 是让promise2 变成 成功态 还是失败
// 此方法为了兼容所有的promise库 尽可能详细 不出错
function resolvePromise(promise2, x, resolve, reject) {
/** PromiseA+ 2.3.2 不能引用同一个对象 会造成死循环*/
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #'));
}
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
// x如果是对象或者函数 说明他有可能是个对象
/** PromiseA+ 2.3.2.2
* 取之可能会报错 then方法可能是由getter定义的
* Object.defineProperty(promise, 'then', {
* get () {
* throw new Error();
* }
* })
* /
let called;
try {
let then = x.then;
if (typeof then === 'function') {
/
* PromiseA+ 2.3.2.2
* let obj = {
* index: 0,
* get then () {
* if (++this.index=== 2) throw error
* }
* }
* obj.then 就会执行
/
// 相当于传进来的值是reject
then.call(
x,
(y) => {
// PromiseA+ 2.3.3.3
// 防止一个promise调用多次 走完成功再走失败 或者走完失败 再走成功 或者一直走成功 或者一直走失败
if (called) return
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(r) => {
// PromiseA+ 2.3.3.3
if (called) return
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (e) {
// PromiseA+ 2.3.3.3
if (called) return;
called = true;
reject(e);
}
} else {
//这里有问题写的
// 普通值 直接成功就好了
resolve(x);
}
}
function isPromise (x) {
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
let x = x.then
if (typeof x.then === 'function') {
return true
}
return false
} catch (error) {
return false
}
}
return false
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallBacks = [];
this.onRejectedCallBacks = [];
let resolve = (value) => {
if (value instanceof Promise) {
// 可能我们初始化的时候传进来的就是个Promise
// 递归解析 直到是普通值为止
// console.log(value)
value.then(resolve, reject);
return false
}
if (this.status === PENDING) {
//PromiseA+ 2.1.1
this.status = FULFILLED;
this.value = value;
this.onFulfilledCallBacks.forEach((fn) => fn());
}
};
let reject = (reason) => {
if (this.status === PENDING) {
//PromiseA+ 2.1.1
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallBacks.forEach((fn) => fn());
}
};
try {
//PromiseA+ 1.1.4
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err;
};
// PromiseA+ 2.2.7
// 为了实现链式调用 创建一个新的promise
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
// 执行then中的方法 可能返回的是一个普通值 或者promise执行
// 我要判断x的类型是不是一个promise 如果是promise的话 我要让这个promise执行
// 并采用他的状态 作为promise的成功或者失败
/
* PromiseA+ 2.2.4*/
setTimeout(() => {
/** PromiseA+ 2.2.7.2*/
try {
// 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
let x = onFulfilled(this.value);
/** PromiseA+ 2.2.7.1*/
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
/** PromiseA+ 2.2.4*/
setTimeout(() => {
/** PromiseA+ 2.2.7.2*/
try {
let x = onRejected(this.reason);
/** PromiseA+ 2.2.7.1*/
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === PENDING) {
this.onFulfilledCallBacks.push(() => {
// 切片编程
/** PromiseA+ 2.2.4*/
setTimeout(() => {
/** PromiseA+ 2.2.7.2*/
try {
// 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
let x = onFulfilled(this.value);
/** PromiseA+ 2.2.7.1*/
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallBacks.push(() => {
/** PromiseA+ 2.2.4*/
setTimeout(() => {
/** PromiseA+ 2.2.7.2*/
try {
// 一旦执行then方法报错 就走到外层then的错误处理中 调用promise2的reject方法中
let x = onRejected(this.reason);
/** PromiseA+ 2.2.7.1*/
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
// 切片编程
});
}
});
return promise2;
}
catch (errCallBack) {
return new Promise((resolve, reject) => {
resolve(this.then(null, errCallBack));
});
}
finally (callback) {
return this.then(
value => new Promise.resolve(callback()).then(() => value),
reason => new Promise.resolve(callback()).then(() => { throw reason })
);
}
}
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let idx = 0;
let arr = []
function processData(y, index){
arr[index] = y
if (arr.length === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
let currentValue = promises[i]
idx++
if (isPromise(currentValue)) {
currentValue.then((y) => {
processData(i)
},reject)
} else {
processData(currentValue, i)
}
}
})
}
Promise.race = function race(entries) {
var Constructor = this; // this 是调用 race 的 Promise 构造器函数。
if (!isArray(entries)) {
return new Constructor(function (_, reject) {
return reject(new TypeError('You must pass an array to race.'));
});
} else {
return new Constructor(function (resolve, reject) {
var length = entries.length;
for (var i = 0; i < length; i++) {
Constructor.resolve(entries[i]).then(resolve, reject);
}
});
}
}
// Promise.resolve 和 Promise.reject 区别
// 传入一个promise的话 resolve
Promise.resolve = function (params) {
return new Promise((resolve, reject) => {
resolve(params)
})
}
Promise.reject = function (params) {
return new Promise((resolve, reject) => {
reject(params)
})
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;

看下这个呢

from blog.

WweiweiSmile avatar WweiweiSmile commented on May 22, 2024

非常棒的一篇文章

from blog.

Vi-jay avatar Vi-jay commented on May 22, 2024

错的,.then执行应该在同一tick,但是你这不是同一tick

from blog.

zhoutengjiao avatar zhoutengjiao commented on May 22, 2024

里实现的Promise是不一致的,想问下

浏览器是 native code microtask,这毕竟是模拟的,其实是macrotask。

from blog.

BoBoooooo avatar BoBoooooo commented on May 22, 2024

好文 点赞

from blog.

307590317 avatar 307590317 commented on May 22, 2024

个人觉得有两个地方需要改正。
第一个就是 constructor中的 resolve方法需要判断resolve函数的参数是不是当前(实测:只能是当前Promise类,不能与其他类共用)Promsie类的实例,如果是,则调用参数的then方法。实现如下

const resolve = data =>{
// 只能是当前Promise类的实例,其他Pormise类的实例则不可
  if(data instanceof Promise){
    return data.then(resolve, reject)
  }
  if(this.state === PENDING){
    this.state = RESOLVED
    this.value = data
    this.onResolvedCbs.forEach(fn => fn())
  }
}

第二个地方是resolvePromise方法中的如果then不是函数的时候,没有必要再给flag赋值。要弄明白什么时候需要给flag赋值,防止回调被调用多次。当把控制权交出去的时候,需要修改flag。由于无法确定resolve还有reject被调用的次数,所以,需要flag来控制回调只执行一次。当then不是函数的时候,就代表不是promise,就不再需要修改flag了。

from blog.

leokang28 avatar leokang28 commented on May 22, 2024

2.3.2 x如果是一个Promise,代码中怎么没体现出来?

from blog.

lixiaohulee avatar lixiaohulee commented on May 22, 2024

@YvetteLau 想确认下

关于Promise.resolve的实现是不是对于thenable对象处理缺少了try catch

如果这样的话
Promise.resolve({ then: function() { throw new Error(11111) } }).then(res => console.log(1, res), err => console.log(err, 5555))

会不会有问题

from blog.

KangChangYi avatar KangChangYi commented on May 22, 2024

finally 那边是不是可以直接这样写:

Promise.prototype.finally = function (onFinally) {
  return this.then(onFinally, onFinally)
}

from blog.

devinRex avatar devinRex commented on May 22, 2024

finally 那边是不是可以直接这样写:

Promise.prototype.finally = function (onFinally) {
  return this.then(onFinally, onFinally)
}

不行哈,比如你看这样的代码

Promise.resolve(2).finally().then((val) => {
	console.log(val);
})

finally不会影响promise一个状态的传递,你这个代码如果onFinally有返回值,就会影响到后面then的回调

from blog.

Larmyliu avatar Larmyliu commented on May 22, 2024

源码复制后报错 @YvetteLau
TypeError: adapter.deferred is not a function at adapter.resolved (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\programmaticRunner.js:13:29) at Object.exports.a fulfilled promise (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\tests\helpers\reasons.js:51:12) at C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\tests\2.2.7.js:58:53 at Array.forEach (<anonymous>) at Suite.<anonymous> (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\tests\2.2.7.js:57:30) at context.describe.context.context (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\node_modules\mocha\lib\interfaces\bdd.js:47:10) at Suite.<anonymous> (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\tests\2.2.7.js:30:5) at context.describe.context.context (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\node_modules\mocha\lib\interfaces\bdd.js:47:10) at Object.<anonymous> (C:\Users\42012\AppData\Roaming\npm\node_modules\promises-aplus-tests\lib\tests\2.2.7.js:15:1) at Module._compile (internal/modules/cjs/loader.js:778:30)

from blog.

Steve-Hawk avatar Steve-Hawk commented on May 22, 2024

好像对 'thenable' 的参数不适用?

from blog.

chenc916 avatar chenc916 commented on May 22, 2024

有个问题
this.value如果是个promise对象的话 第一个then拿到的永远是reslove的回调,结果是这个promise对象
实际应该是要根据promise的状态来判断是resolve还是reject.以及是value还是reason.

from blog.

Chorer avatar Chorer commented on May 22, 2024

2.3.2 x如果是一个Promise,代码中怎么没体现出来?

promise 本身就是一种 thenable,下面统一处理了,效果一样的,只是没有按照规范那样实现

from blog.

Chorer avatar Chorer commented on May 22, 2024

resolvePromise中self是多余的,好几次以为是自身对象,debug走一遍之后发现是window,再往下面看的时候发现并没有用到。

确实用不到,resolvePromise 是在全局中声明的函数,this 指向的是全局对象,除非传 promise 实例给 resolvePromise,否则它根本拿不到 promise 实例

from blog.

zhuokuang avatar zhuokuang commented on May 22, 2024

``> ```js

let x = new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
resolve(2);
})
);
}).then(res => {
console.log(res);
});


我发现一个问题就是,这个在浏览器的Promise中,和这里实现的Promise是不一致的,想问下这是新规范吗

确实,我也发现了这个问题,然后去网上找 Promise 实现,发现很多手写 Promise 实现都没有考虑给 resolve 函数传另一个 promise 对象的情况。

const p1 = new Promise((resolve, _reject) => {
  setTimeout(resolve, 1000, "p1");
});

const p2 = new Promise((resolve, _reject) => {
  resolve(p1);
});

p2.then((res) => {
  console.log(res);
});

对于 es6 的 Promise,输出的是:p1;
而对于楼主手写的 Promise,输出的则是:Promise { status: 'pending', onFulfilled: [], onRejected: [] }
最后在大佬们的回复中找到了解决方案,感谢提供解决方案的大佬们!

from blog.

Benjamin-Zh avatar Benjamin-Zh commented on May 22, 2024

里实现的Promise是不一致的,想问下

浏览器是 native code microtask,这毕竟是模拟的,其实是macrotask。

可以使用 window.queueMicroTask(callback) 来队列 microtask

from blog.

summerhll avatar summerhll commented on May 22, 2024

from blog.

yurnery avatar yurnery commented on May 22, 2024

``> ```js

let x = new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
resolve(2);
})
);
}).then(res => {
console.log(res);
});


我发现一个问题就是,这个在浏览器的Promise中,和这里实现的Promise是不一致的,想问下这是新规范吗

确实,我也发现了这个问题,然后去网上找 Promise 实现,发现很多手写 Promise 实现都没有考虑给 resolve 函数传另一个 promise 对象的情况。

const p1 = new Promise((resolve, _reject) => {
  setTimeout(resolve, 1000, "p1");
});

const p2 = new Promise((resolve, _reject) => {
  resolve(p1);
});

p2.then((res) => {
  console.log(res);
});

对于 es6 的 Promise,输出的是:p1; 而对于楼主手写的 Promise,输出的则是:Promise { status: 'pending', onFulfilled: [], onRejected: [] }。 最后在大佬们的回复中找到了解决方案,感谢提供解决方案的大佬们!

我也发现了网上的实现都没处理这种这种情况, 只处理了 then 中返回 promise的情况, 如果在 new Promise的时候, 直接 resolve 了另一个 promise, 网上的实现都有问题, 但是能通过 promise a+ 测试

from blog.

summerhll avatar summerhll commented on May 22, 2024

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.