提问者:小点点

如何在ES6[重复]中将回调代码转换为promise


我正在学习ES6标准,所以我从一个非常基本的示例代码开始。

JavaScript中存在回调地狱,所以这次我确实想避免使用回调。但是我遇到了一个问题,我不知道如何将回调样式代码转换为承诺。

例如,如果我有如下所示的代码

module.exports = (x, y, callback) => {
  try {
    if (x < 0 || y < 0) {
      throw new Error('Rectangle dimensions are wrong.');
    } else {
      callback(null, {
        perimeter() {
          return (2 * (x + y));
        },
        area() {
          return (x * y);
        },
      });
    }
  } catch (error) {
    callback(error, null);
  }
};

我应该如何将它转换为ES6中的promise?那是一种将回调转换为承诺的推荐行为吗?

我读过这个例子,但我实际上被结果弄糊涂了。我想,在我开始重写我对承诺的回调之前,我需要先了解这一点。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('Resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// Resolved 

我的理解是,promise在创建后立即运行。但是我不知道为什么then方法中的代码会最后运行。


共3个答案

匿名用户

现有的答案成为延迟反模式的牺牲品。我会避免这种方法,因为它不必要地冗长,并且没有利用完整的Promise API。另一个答案使用允诺。实际上,只有当您无法更改使用回调样式编写的代码(例如使用第三方脚本)时,才有必要使用允诺。

你在问两个问题,其中第二个问题是为什么许诺的行为方式,你在你所给出的例子中看到。为了找到这个问题的答案,我建议你使用许多现有的关于这类性质的问题。比如,承诺不就是回调吗?

关于您的第一个问题,即如何重构代码以使用承诺,我的建议如下:

module.exports = (x, y) => {
  if (x < 0 || y < 0) {
    return Promise.reject(new Error('Rectangle dimensions are wrong.'));
  } else {
    return Promise.resolve({
      perimeter() {
        return (2 * (x + y));
      },
      area() {
        return (x * y);
      },
    });
  }
};

// e.g. success
createRectangle(10, 10)
  .then(rect => {
    console.log(rect.area()) //=> 100
  })

// e.g. failure
createRectangle(-1, -1)
  .catch(err => {
    console.log(err) //=> "Error: Rectangle dimensions are wrong."
  })

由于函数本身并不依赖于异步操作的完成,我们可以使用帮助器方法Promise#resolvePromise#reject从函数返回一个承诺,该承诺表示创建“矩形”对象的成功或失败。这将产生一个新的承诺,其状态分别是通过一个值或一个错误来解决或拒绝。

匿名用户

module.exports = (x, y, callback) => {
  new Promise(function(resolve, reject) {
    if (x < 0 || y < 0) reject(new Error('Rectangle dimensions are wrong.'))
    else resolve({
      perimeter() {
        return (2 * (x + y));
      },
      area() {
        return (x * y);
      }
    })
  })
  .then(callback)
  .catch(callback)
}

记住“。then”和“。catch”是异步的。

匿名用户

这是一个重要的课题。为了以同步方式进行函数编码,使用承诺的目的是将callback中的逻辑移动到then阶段。因此,尽管可以,但您不应该在承诺本身内处理逻辑,而应该在然后阶段处理。这种思路有助于我们创建一个通用的允诺实用函数,它适用于所有特定类型的回调结构。在您的示例中,回调类型是节点标准错误优先类型。因此根据下面的代码

module.exports = (x, y, callback) => {
  try {
    if (x < 0 || y < 0) {
      throw new Error('Rectangle dimensions are wrong.');
    } else {
      callback(null, {
        perimeter() {
          return (2 * (x + y));
        },
        area() {
          return (x * y);
        },
      });
    }
  } catch (error) {
    callback(error, null);
  }
};

一般的允诺函数应如下工作;

null

var moduleExports = (x, y, callback) => {
  try {
    if (x < 0 || y < 0) {
      throw new Error('Rectangle dimensions are wrong.');
    } else {
      callback(null, {
        perimeter() {
          return (2 * (x + y));
        },
        area() {
          return (x * y);
        },
      });
    }
  } catch (error) {
    callback(error, null);
  }
};

function promisfy(fun, ...args){
  return new Promise((v,x) => fun(...args, (err,data) => !!err ? x(err) : v(data)));
}

var p = promisfy(moduleExports,4,5);
p.then(val => console.log(val,val.area(),val.perimeter()), err => console.log(err));

// p.then(val => callback(null,val), err => callback(err))