GVKun编程网logo

Node.js推迟Promisify +猫鼬(nodejs 延时)

12

对于Node.js推迟Promisify+猫鼬感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍nodejs延时,并为您提供关于Callback与Promise间的桥梁——promisify、Ex

对于Node.js推迟Promisify +猫鼬感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍nodejs 延时,并为您提供关于Callback 与 Promise 间的桥梁 —— promisify、Express中promisify将异步api转换成promise的形式、javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回、javascript – Promise.promisify不是一个函数的有用信息。

本文目录一览:

Node.js推迟Promisify +猫鼬(nodejs 延时)

Node.js推迟Promisify +猫鼬(nodejs 延时)

是否有人使用过nodejs模块“ deferred”和“
mongoose”?我试图让deferred.promisify方法可以在猫鼬模型的函数上工作,以便我可以轻松地将它们链接起来,但是会遇到一些麻烦。具体来说,我想对findfindById函数进行赋值处理,以便可以通过ObjectID链接查找另一个文档引用的一个文档。

这就是我所拥有的:https :
//gist.github.com/3321827

但是,这似乎并不理想,因为getAppPermissionsand
getApplication函数似乎只不过是猫鼬模型的findand和findById方法的包装器。

我尝试仅通过传递函数来实现承诺,但Object #<Object> has no method''_applyNamedScope''由于this不再绑定到正确的对象,因此出现了一个错误,似乎是由错误引起的。也许我需要使用underscore.bind?有没有人在这方面取得任何成功,还是我应该坚持现在的工作?

答案1

小编典典

Mariusz的答案非常接近。这是在这种情况下最终对我有用的东西,希望其他人可以从中学到:

// I put this in my model file so I didn''t have to worry about repeating itvar userProto = mongoose.model(''User'');userProto.pFind = deferred.promisify(userProto.find);userProto.pFindOne = deferred.promisify(userProto.findOne);

Callback 与 Promise 间的桥梁 —— promisify

Callback 与 Promise 间的桥梁 —— promisify

Promise 自问世以来,得到了大量的应用,简直是 javascript 中的神器。它很好地解决了异步方法的回调地狱、提供了我们在异步方法中使用 return 的能力,并将 callback 的调用纳入了自己的管理,而不是交给异步函数后我们就无能为力了(经常有 callback 被莫名调用两次而导致程序出错)。

今天要介绍的是 Promisify,就是回调函数与 Promise 间的桥梁。

1. promisify 介绍

什么是 promisify 呢?顾名思义,就是“promise 化”,将一个不是promise的方法变成 promise 。举个例子:

// 原有的callback调用
fs.readFile(''test.js'', function(err, data) {
    if (!err) {
        console.log(data);
    } else {
        console.log(err);
    }
});

// promisify后
var readFileAsync = promisify(fs.readFile);
readFileAsync(''test.js'').then(data => {
    console.log(data);
}, err => {
    console.log(err);
});

这两个方法效果上是等价的,但是从掌控性来说的话,我更喜欢后面的写法。

那么什么样的方法可以通过 promisify 变成 promise 呢?这里就需要介绍一个名词,nodeCallback。什么样的 callback 叫 nodeCallback ?

nodeCallback 有两个条件:1. 回调函数在主函数中的参数位置必须是最后一个;2. 回调函数参数中的第一个参数必须是 error 。举个例子:

  1. 回调函数在主函数中的参数位置
// 正确
function main(a, b, c, callback) {
    
}

// 错误
function main(callback, a, b, c) {
    
}
  1. 回调函数参数中的第一个参数必须是 error
// 正确
function callback(error, result1, result2) {
    
}

// 错误
function callback(result1, result2, error) {
    
}

这样,通过 nodeCallback ,我们定义了一个能被 promisify 的函数的格式,即,满足 nodeCallback 形式的方法,我们可以通过 promisify 来让它变成一个返回 promise 的方法。

2. promisify 的实现

下面我们来根据上述条件来手动实现一个 promisify 。

首先 promisify 需要返回一个 function ,并且这个 function 要返回一个 promise

var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments);
        })
    }
}

其次,原 func 的最后一个参数是 callback

var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments, function() {
                resolve(arguments);
            });
        })
    }
}

然后,回调函数中的第一个参数是 error 标记

var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise((resolve, reject) => {
            return func.call(ctx, ...arguments, function() {
                var args = Array.prototype.map.call(arguments, item => item);
                var err = args.shift();
                if (err) {
                    reject(err);
                } else {
                    resolve(args);
                }
            });
        })
    }
}

最后,做一些优化,比如 this 作用域的自定义、回参只有一个时不返回数组

var promisify = (func, ctx) => {
    // 返回一个新的function
    return function() {
        // 初始化this作用域
        var ctx = ctx || this;
        // 新方法返回的promise
        return new Promise((resolve, reject) => {
            // 调用原来的非promise方法func,绑定作用域,传参,以及callback(callback为func的最后一个参数)
            func.call(ctx, ...arguments, function() {
                // 将回调函数中的的第一个参数error单独取出
                var args = Array.prototype.map.call(arguments, item => item);
                var err = args.shift();
                // 判断是否有error
                if (err) {
                    reject(err)
                } else {
                    // 没有error则将后续参数resolve出来
                    args = args.length > 1 ? args : args[0];
                    resolve(args);
                }
            });
        })
    };
};

测试

// nodeCallback方法func1
var func1 = function(a, b, c, callback) {
    callback(null, a+b+c);
}
// promise化后的func2
var func2 = promisify(func1);
// 调用后输出6
func1(1, 2, 3, (err, reuslt) => {
    if (!err) {
        console.log(result); //输出6
    }
})
func2(1, 2, 3).then(console.log); //输出6

以上便是 promisify 的介绍和实现,事实上有很多用 callback 来实现异步的第三方库提供的方法都是按照 nodeCallback 格式的,所以它们都可以通过 promisify 来让它变成 promise ,在遇到这些方法的时候就可以更灵活地使用啦。

iKcamp官网:http://www.ikcamp.com

访问官网更快阅读全部免费分享课程:《iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享》。
包含:文章、视频、源代码

iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。

【11月11号】上海iKcamp最新活动

报名地址:http://www.huodongxing.com/ev...

“天天练口语”小程序总榜排名第四、教育类排名第一的研发团队,面对面沟通交流。

Express中promisify将异步api转换成promise的形式

Express中promisify将异步api转换成promise的形式

原代码

app.get('/todo', (req, res) => {
    fs.readFile('./db.json', 'utf8', (err, data) => {
        if(err) {
            res.status(500).end()
        } else {
            res.status(200).json(JSON.parse(data))
        }
    })
})

app.get('/todo/:id', (req, res) => {
    fs.readFile('./db.json', 'utf8', (err, data) => {
        if(err) {
            res.status(500).end()
        } else {
            let db = JSON.parse(data)
            let todo = db.todos.find(item => item.id === Number.parseInt(req.params.id))
            if(!todo) {
                return res.status(404).end()
            }
            res.status(200).json(todo)
        }
    })
})

promisify形式代码

以上代码其实可以将读取文件部分的代码封装,但是该代码为异步回调函数,可以将这种callback形式的异步回调api通过promisify转换成promise形式,便于封装
封装的函数

const fs = require('fs')
const path = require('path')
// 将callback这种形式的异步api转换成promise的方式
const { promisify } = require('util')
const readFile = promisify(fs.readFile)

const dbPath = path.join(__dirname, './db.json')

exports.getDb = async () => {
    const data = await readFile(dbPath, 'utf8')
    return JSON.parse(data)
}

调用该函数

const { getDb } = require('./db');

app.get('/todo', async (req, res) => {
    try {
        const db = await getDb()
        res.status(200).json(db.todos)
    } catch(err) {
        res.status(500).json({
            error: err.message
        })
    }
})

app.get('/todo/:id', async (req, res) => {
    try {
        const db = await getDb()
        let todo = db.todos.find(item => item.id === Number.parseInt(req.params.id))
        if(!todo) {
            return res.status(404).end()
        }
        res.status(200).json(todo)
    } catch(err) {
        res.status(500).json({
            error: err.message
        })
    }
})

javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回

javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回

当我在服务器上收到发布请求以创建新游戏时,我会执行几个查询.首先,我搜索用户是否已经在游戏中,如果是,则返回游戏.否则,我搜索一个开放的游戏,其中某人正在等待对手并返回该游戏,如果是这样的话.最后,如果没有找到上述状态的游戏,我会创建一个新游戏并返回.所以我的代码看起来像这样:

.post( function(req,res,next){

  ...findUsersExistingGame...

  .then(function(game){
    if(game){ return res.send(game); }
    else{
        return ...findUserWaitingForOpponentsGame...
    }
  }
  .then(function(game){
    if(game){ return res.send(game); }
    else{
        return ...createNewGame...
    }
  })
  .then(function(game){
        return res.send(game);
  })
  .catch(function(err){
       return next(err);
  });

我最终会将每个函数重构为辅助函数以提高可读性,但我需要首先弄清楚链接.我的问题是,如果我在承诺链中找到一个游戏(即用户现有的游戏或其他等待对手的用户),那么我将返回res.send(游戏);但是,第三个.then将抛出一个错误,因为我之前的.then()语句返回undefined.如果我想做一个res.send(游戏),我如何早早退出承诺链?

选项1:我已经看到了抛出错误并明确捕获它的建议,但这种感觉从根本上说是错误的,使用错误来控制流量.

选项2:我可以做类似的事情而不是链接承诺,但这类似于“承诺/回调地狱”:

.post( function(req,next){

  ...findUsersExistingGame...

  .then(function(game){
    if(game){ return res.send(game); }
    else{
        ...findUserWaitingForOpponentsGame...
        .then(function(game){
            if(game){ return res.send(game); }
            else{
                return ...createNewGame...
                .then(function(game){
                    return res.send(game);
                });
            }
        })
    }
  }

还有另一种方式(最好是在ES5中,因为我仍然试图从根本上理解承诺,但ES6的答案也是受欢迎的)?

解决方法

这里的主要问题是,沿途的每个步骤都有三个可能的返回值:

>游戏发现
>游戏尚未找到
>寻找游戏时出错

由于promises只是自然地分离错误而没有错误,只要你想以不同的方式处理这三个单独的返回中的每一个,你就会添加一些自己的分支逻辑.

要使用promise结果干净地进行分支需要额外的嵌套级别,并且通常没有理由避免它,因为它将使您的代码最容易遵循并理解其逻辑.

.post( function(req,next) {
    findUsersExistingGame(...).then(function(game) {
        if (game) return game;
        return findUserWaitingForOpponentsGame(...).then(function(game) {
            if (game) return game;
            // createNewGame() either resolves with a valid game or rejects with an error
            return createNewGame(...);
        });
    }).then(function(game) {
        res.send(game);
    },function(err) {
        // send an error response here
    });
});

请注意这是如何简化每个阶段的返回,并返回下一个嵌套的承诺,使事物链,并集中处理将响应发送到一个地方以减少整体代码.

现在,您可以通过让每个函数接受之前的游戏值并让他们检查是否已经存在有效游戏来隐藏其中一些逻辑,则他们什么也不做:

.post( function(req,next) {
    findUsersExistingGame(args)
        .then(findUserWaitingForOpponentsGame)
        .then(createNewGame)
        .then(function(game) {
            res.send(game);
        },function(err) {
            // send an error response here
        });
});

但是,在findUserWaitingForOpponentsGame()中,你必须接受findUsersExistingGame()解析的确切参数,你必须检查游戏是否有效.

function findUserWaitingForOpponentsGame(args) {
    if (args.game) {
        return Promise.resolve(args);
    } else {
        return doAsyncFindUserWaitingForOpponentsGame(args);
    }
}

每个函数都将使用args对象解析,该对象上有任何公共参数,并且具有每个级别可以检查的.game属性.虽然这为您提供了一个很好的清洁控制流,但它确实在每个函数中创建了额外的代码,它强制每个函数接受作为前一个函数输出的参数(因此您可以直接链接).你可以决定哪个更好.

javascript – Promise.promisify不是一个函数

javascript – Promise.promisify不是一个函数

我写了这样的 JavaScript:

var keys=null;
var promise=Promise.promisify(alchemyapi.keywords("url",myUrl,{},function(response) {
    var keywords = { url:myUrl,response:JSON.stringify(response,null,4),results:response['keywords'] };
                return keywords;
            }));
promise.then(
                (result)=>{
                    var keys=result;
                    console.log(keys);
                },(error)=>console.log(error)
            );

我正在使用AlchemyAPI并尝试将数据存储到我的数据库中
我应该怎么做?

解决方法

您应该能够通过删除.promisify来使用Promise来返回预期的结果.promisify不是内置的Promise方法;替换传递关键字以在Promise构造函数中解析返回

var keys = null,promise = new Promise(function(resolve) {
    alchemyapi.keywords("url",function(response) {
      var keywords = {url: myUrl,response: JSON.stringify(response,results:response['keywords'] 
                     };
      resolve(keywords);
      // error handling ?
    })
  }).then(function(result) {
      keys = result;
      console.log(keys)
  },function(err) {
      console.log(err)
  })

我们今天的关于Node.js推迟Promisify +猫鼬nodejs 延时的分享就到这里,谢谢您的阅读,如果想了解更多关于Callback 与 Promise 间的桥梁 —— promisify、Express中promisify将异步api转换成promise的形式、javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回、javascript – Promise.promisify不是一个函数的相关信息,可以在本站进行搜索。

本文标签: