如何将嵌套回调转换为promise?

时间:2017-02-01 14:39:48

标签: javascript node.js promise bluebird pg-promise

最近我开始在bluebird库中使用pg-promise。我一直在每个回调中嵌套回调和处理err。我发现承诺中的catch陈述看起来非常整洁。我不确定是否可以将此代码转为承诺基础?

username = username.toUpperCase();
let text = "SELECT * FROM users WHERE username = $1";
let values = [username];
database.one(text, values).then(function (userObject) {
  // ANY WAY TO TURN this nested bycrypt into promise chain?
  bcrypt.compare(password, userObject.password, function (err, same) {
    if (err) {
      return next(err, null);
    }
    if (!same) {
      return next(new Error("Password mismatched!"), null);
    }
    const serializeObject = {_id: userObject._id};
    return next(null, serializeObject);
  });
}).catch(function (err) {
  return next(err, null);
});

2 个答案:

答案 0 :(得分:4)

我想使用bluebirds promisify,你会像这样宣传bcrypt.compare(你不必使用名称的Async部分)

public class MainActivity extends AppCompatActivity {

ListView listView;
Button sync;
ProgressDialog progressDialog;
String name, phone;

ArrayList<Contact_list> listitem;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);



    listitem = new ArrayList<Contact_list>();

    listView = (ListView) findViewById(R.id.listViewID);
    registerForContextMenu(listView);

    sync= (Button) findViewById(R.id.syncID);
    sync.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            // GET CONTACTS DATA


            GetContactsIntoArrayList();


            listView.setAdapter(new Custom_adapter(MainActivity.this, listitem));

            Toast.makeText(MainActivity.this, "import", Toast.LENGTH_SHORT).show();
        }
    });
}

public void GetContactsIntoArrayList(){
    Cursor cursor;
    cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null, null, null);

    while (cursor.moveToNext()) {

        name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));

        phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));


        listitem.add(new Contact_list(name,phone));



        listView.setAdapter(new Custom_adapter(MainActivity.this, listitem));

    }

    cursor.close();

    listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {

        public boolean onItemLongClick(AdapterView<?> arg0, View v,
                                       int index, long arg3) {
            // TODO Auto-generated method stub

            Log.v("long clicked","pos: " + index);


            //Log.d("tag", "message");
            String str=listView.getItemAtPosition(index).toString();

            Log.d("long click sucessfull: " ,str);
            return true;
        }
    });

}

 @Override
 public void onCreateContextMenu(ContextMenu menu, View v,ContextMenu.ContextMenuInfo menuInfo)
   {

       super.onCreateContextMenu(menu, v, menuInfo);
       menu.setHeaderTitle("Select The Action");
       menu.add(0, v.getId(), 0, "Call");
       menu.add(0, v.getId(), 0, "Send SMS");

}




@Override
public boolean onContextItemSelected(MenuItem item)
{


    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();

    //  info.position will give the index of selected item
    int IndexSelected=info.position;
    if(item.getTitle()=="Call")
    {

        // Code to execute when clicked on This Item
    }
    else if(item.getTitle()=="Send SMS")
    {

        // Code to execute when clicked on This Item
        //
                                                            }
        else
        {
            return false;
        }
        return true;


    }


}
  

因为第一个.then中的let compareAsync = Promise.promisify(bcrypt.compare); 需要在第二个中使用。然后,你不能通过返回compareAsync简单地链接.then,因为那样下一个。然后不会。有权访问userObject

一个修正,是使用一个变量,它将在两个范围内。但是(但是)

userObject

另一个(在我看来更干净)选项是一个嵌套的.then

username = username.toUpperCase();
let text = "SELECT * FROM users WHERE username = $1";
let values = [username];
let uo; //hacky the outer scoped variable
database.one(text, values).then(function (userObject) {
    uo = userObject;
    return compareAsync(password, userObject.password);
}).then(function(same) {
    if (!same) {
        throw new Error("Password mismatched!");
    }
    const serializeObject = {_id: uo._id};
    return next(null, serializeObject);
}).catch(function (err) {
    return next(err, null);
});

注意:bluebird有一个promisifyAll函数...它在一个对象中传播函数,并在函数名称中添加(默认情况下)username = username.toUpperCase(); let text = "SELECT * FROM users WHERE username = $1"; let values = [username]; database.one(text, values).then(function (userObject) { return compareAsync(password, userObject.password) // [optional] following three lines to generate a "nicer" error for compare failure .catch(function(err) { throw "bcrypt.compare failed"; }) // nested .then to pass on the userObject and same at the same time .then(function (same) { return { same: same, userObject: userObject }; }); }).then(function (result) { let same = result.same, userObject = result.userObject; if (!same) { throw new Error("Password mismatched!"); } let serializeObject = { _id: userObject._id }; return next(null, serializeObject); }).catch(function (err) { return next(err, null); }); 后缀 - 我相信你可以决定一个不同的后缀名,但是文档会告诉你更多

在宣传单一功能时,您自己声明名称 - 以上内容可以轻松实现

Async

然后您只需使用代码为let trumpIsBigly = Promise.promisify(bcrypt.compare);

trumpIsBigly
  

最后一种可能性

手工推出的promisified compareAsync(主要取决于vitaly-t&#39的答案,但附加内容)

compareAsync

现在,只有在没有错误的情况下,compareAsync将解析为传入值function compareAsync(password1, password2, inValue) { return new Promise(function (resolve, reject) { bcrypt.compare(password1, password2, function (err, same) { err = err || (!same && new Error("Password mismatched!")); if (err) { reject(err); } else { resolve(inValue); } }); }); } AND 同样如此

inValue

这使得&#34;链&#34;很简单!

答案 1 :(得分:1)

这是为了扩展@ Jaromanda的答案,以防你只使用那一个功能,只想看看如何手动宣传它。​​

function samePassword(password1, password2) {
    return new Promise(function (resolve, reject) {
        bcrypt.compare(password1, password2, (err, same) => {
            err = err || (!same && new Error("Password mismatched!"));
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });

    });
}

db.one(text, values)
    .then(userObject => {
        return samePassword(password, userObject.password);
    })
    .catch(error => {
        return next(error, null);
    });

除此之外,promisify方法是可行的方法。但要理解它有效地做了什么总是好的;)