Javascript 如何在ES6中将回调代码转换为承诺

Javascript 如何在ES6中将回调代码转换为承诺,javascript,asynchronous,callback,promise,ecmascript-6,Javascript,Asynchronous,Callback,Promise,Ecmascript 6,我正在学习ES6标准,所以我从一个非常基本的示例代码开始 JavaScript中存在回调hell,所以这次我确实希望避免使用回调。但我遇到了一个问题,我真的不知道如何将回调风格的代码转换为承诺 例如,如果我有如下代码 module.exports = (x, y, callback) => { try { if (x < 0 || y < 0) { throw new Error('Rectangle dimensions are wrong.');

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

JavaScript中存在回调hell,所以这次我确实希望避免使用回调。但我遇到了一个问题,我真的不知道如何将回调风格的代码转换为承诺

例如,如果我有如下代码

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);
  }
};
我的理解是,
Promise
在创建后立即运行。但是我不知道为什么
then
方法中的代码会最后运行。

module.exports=(x,y,callback)=>{
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)
}
新承诺(功能(解决、拒绝){ 如果(x<0 | | y<0)拒绝(新错误('矩形尺寸错误')) 否则解决({ 周长(){ 回报率(2*(x+y)); }, 面积(){ 返回(x*y); } }) }) .然后(回调) .catch(回调) }

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

承诺确实很好,但一开始可能会有点混乱,请检查以下代码:

module.exports = (x, y) => {
var deferred = q.defer();// this will be our promise
  try {
    if (x < 0 || y < 0) {
      //return an error to be catched by catch method
      deferred.reject(new Error('Rectangle dimensions are wrong.'));
    } else {
      //return the event to the next function with this value
      deferred.resolve({
        perimeter() {
          return (2 * (x + y));
        },
        area() {
          return (x * y);
        },
      });
    }
  } catch (error) {
    deferred.reject(error);
  }

 return deferred.promise; //Here return the promise
};

//You will use it like this
module(x,y)
.then(callback)
.then(function(data){
 })
.catch(function(error){
});
module.exports=(x,y)=>{
var deferred=q.deferred();//这将是我们的承诺
试一试{
if(x<0 | | y<0){
//返回要由catch方法捕获的错误
拒绝(新错误('矩形尺寸错误');
}否则{
//使用此值将事件返回到下一个函数
推迟,解决({
周长(){
回报率(2*(x+y));
},
面积(){
返回(x*y);
},
});
}
}捕获(错误){
延迟。拒绝(错误);
}
return deferred.promise;//此处返回承诺
};
//你会像这样使用它
模块(x,y)
.然后(回调)
.then(功能(数据){
})
.catch(函数(错误){
});
在我的示例中,当您调用模块时,您将立即获得承诺,但代码尚未执行,在代码执行后,您将在“then”方法中获得事件,或者如果捕获中发生了什么事情

我真的很喜欢q库来处理承诺,让您能够控制如何返回错误,并在发生错误时停止链。基本上,您可以更好地控制您的函数流


希望对您有所帮助

这是一个重要的话题。为了以同步的方式进行功能编码,使用promises的目的是将
回调
中的逻辑移动到
然后
阶段。因此,尽管可以,但您不应该在承诺本身中处理逻辑,而是在
然后
阶段。这种思维方式帮助我们创建一个通用的promisify实用程序函数,它适用于所有特定类型的回调结构。在您的情况下,回调类型是节点标准错误第一种类型。所以按照下面的代码

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);
  }
};
module.exports=(x,y,回调)=>{
试一试{
if(x<0 | | y<0){
抛出新错误('矩形尺寸错误');
}否则{
回调(null{
周长(){
回报率(2*(x+y));
},
面积(){
返回(x*y);
},
});
}
}捕获(错误){
回调(错误,空);
}
};
一般承诺功能应如下所示:

var moduleExports=(x,y,回调)=>{
试一试{
if(x<0 | | y<0){
抛出新错误('矩形尺寸错误');
}否则{
回调(null{
周长(){
回报率(2*(x+y));
},
面积(){
返回(x*y);
},
});
}
}捕获(错误){
回调(错误,空);
}
};
函数promisfy(乐趣,…参数){
返回新承诺((v,x)=>fun(…args,(err,data)=>!!err?x(err):v(data));
}
var p=promisfy(模块出口,4,5);
p、 然后(val=>console.log(val,val.area(),val.permiture()),err=>console.log(err));

//p.then(val=>callback(null,val),err=>callback(err))
现有的答案会成为问题的牺牲品。我会避免使用这种方法,因为它不必要地冗长,并且没有利用FullPromise API。另一个答案是使用Promission。只有当您无法更改使用回调样式编写的代码(例如,使用第三方脚本)时,才需要使用Promission

你在问两个问题,第二个问题是,为什么承诺会像你在给定的例子中看到的那样。为了找到这个问题的答案,我建议你使用许多现有的关于这个性质的问题。比如说,

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

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."
  })
module.exports=(x,y)=>{
if(x<0 | | y<0){
返回承诺。拒绝(新错误('矩形尺寸错误');
}否则{
还愿({
周长(){
回报率(2*(x+y));
},
面积(){
返回(x*y);
},
});
}
};
//例如成功
createRectangle(10,10)
.然后(rect=>{
console.log(rect.area())/=>100
})
//例如失败
createRectangle(-1,-1)
.catch(错误=>{
console.log(err)//=>“错误:矩形尺寸错误。”
})

由于函数本身并不依赖于异步操作的完成,我们可以使用helper方法,并从函数返回一个承诺,表示创建“矩形”对象的成功或失败。这些产生了一个新的承诺,其状态被解析或拒绝,分别带有一个值或一个错误。

如果您阅读了承诺/a+的规范,请特别注意2.2.4和相关的注释3.1-基本上是
。然后
回调是异步的,这正是我想要的。我会查看其他一些关于承诺的帖子。
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."
  })