不使用new关键字创建Promise对象

4

在观看了 fun fun function 后,我决定不再使用 new 关键字。

但是这里有一个基础示例,展示如何使用 Promise:

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

问:如何在不使用 new 关键字的情况下创建一个 Promise?


1
你为什么决定不使用 new 关键字?你看了视频并理解了吗?你可以完全按照视频中的示例操作...不确定你想要实现什么。 - skyline3000
2
Promise 是一个对象。如果是这样,它应该使用 new 来创建这个对象的新实例... - Sergey
5
不要相信你在 YouTube 上观看的所有视频。 - robertklep
@Sergey,new 不会创建 Promise 对象的新实例。Promise 是一个构造函数(即一个函数)。你可以创建 Promise.prototype实例,而不是 Promise 的实例。 - trincot
1
似乎避免使用支持的、易于理解和简单的创建 Promise 的方式是一个相当无意义的目标。 - jfriend00
4个回答

4
作为一个纯学术问题,你可以通过创建一个thenable(不需要使用new),然后使用Promise.resolve将该thenable转换为完整的promise来解决new的问题。

function createPromise(executor) {
    let callback;
    function resolve(resolution, arg) {
        Promise.resolve().then(function () {
            callback[resolution](arg);
        });
    }
    try {
        executor(resolve.bind(null, "fulfill"), resolve.bind(null, "reject"));
    } catch(e) {
        resolve("reject", e);
    }
    return Promise.resolve({ 
        then: function (fulfill, reject) {
            callback = { fulfill, reject };
        }
    });
}

// Demo
var prom1 = createPromise(function (resolve, reject) {
    setTimeout(function () { resolve("Stuff worked!") }, 1000);
});
var prom2 = createPromise(function (resolve, reject) {
    setTimeout(function () { reject("It broke") }, 1000);
});

prom1.then(function (v) { console.log(v); });
prom2.catch(function (err) { console.log(err) });
console.log('waiting for promises to resolve');

一些人有避免使用new的原因,但如果这导致了上述代码,那么显然应该允许一些例外情况。除非有更好的方法来创建Promise而不使用new,否则必须再次实现一些Promise的特性(例如try ... catchthen回调的异步调用),只为解决new的问题。这似乎是一个糟糕的想法。
结论:只需使用new来创建新的Promise。

1
为什么这个如此复杂?为什么不直接使用工厂函数:function createPromise(executor) {return new Promise(executor);} - jfriend00
2
因为问题要求不使用 new 来完成吗? - trincot

2

使用 async/await

const getPromise = async () => {
    // do a thing, possibly async, then…

    if (/* everything turned out fine */) {
        return 'Stuff worked!'
    } else {
        throw 'It broke'
    }
});
const promise = getPromise()

请注意,您不能只调用Error,在NodeJS中不使用new关键字调用构造函数会将垃圾抛出到global对象中(在浏览器JS中则是抛出到window对象中)。您必须使用new Error。希望我没有为您创建一个全新的问题。
此外,请注意,async/await只是一种语法糖,代码将始终使用new运行。我建议不要完全按照建议去做。诚然,new是有害的,但有时需要使用以避免过度复杂化事情。

2
当然,这是认真的回答,问题出在哪里? - dzuremar
2
没有问题;-) - trincot
1
实际上,他也建议不要使用async await。https://youtu.be/-Yv2qljLrns?t=4m9s - Phillip Senn
呃,是啊,发生了,有点尴尬。感谢你刺激我。 - dzuremar
3
创建新错误时无需使用new关键字,Error(...)也可以充当一个工厂函数(参考链接)。 - robertklep
显示剩余4条评论

1
MDN的Promise.resolve()Promise.reject()手册展示了这些函数如何返回thenable。
以下代码片段进一步展示了它们如何用于使myFunc包装_myFunc以返回一个thenable。

'strict';

function _myFunc(tf){
  if (tf)
    return; 
  throw new Error('flubbed it');
}
function myFunc(tf){
  try { return Promise.resolve(_myFunc(tf));}
  catch(e) { return Promise.reject(e);}
}

function main() {
  try {
    _myFunc(false);
    console.log('SUCCESS');
  } catch (e) {
    console.log(`FAILED: ${e.message}`);
  }

  try {
    _myFunc(true);
    console.log('SUCCESS');
  } catch (e) {
    console.log(`FAILED: ${e.message}`);
  }

  myFunc(false)
    .then(()=>{ console.log('success'); })
    .catch((e)=>{ console.log(`failed: ${e.message}`); });

  myFunc(true)
    .then(()=>{ console.log('success'); })
    .catch((e)=>{ console.log(`failed: ${e.message}`); });

}

main();

然而,由于没有承诺,因此也没有await,我们在同步方面回到了失败之塔(pyramid of doom),如输出中所示。
FAILED: flubbed it
SUCCESS
success
failed: flubbed it

最后两个结果的顺序颠倒了。这是因为JS解释器将thenable的使用视为异步运行命令的指令。
总之,Promise的伟大之处在于能够使用awaitPromise.allPromise.race等功能,这些功能需要具有状态的Promise,因此需要使用new Promise(...)

0
你可以使用一个包装函数:
const Guarantee = function () {
  var _resolve = null
  var _reject = null

  var promise = new Promise(function (resolve, reject) {
    _resolve = resolve
    _reject = reject
  })

  promise.resolve = function () {
    _resolve.apply(promise, arguments)
  }

  promise.reject = function () {
    _resolve.apply(promise, arguments)
  }

  return promise
}

function doSomething () {
  const promise = Guarantee()

  setTimeout(function () {
    promise.resolve('123')
  }, 1000)

  return promise
}

doSomething()
  .then(function (data) {
    console.log(data)
  })

享受吧!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接