Ben*_*aum 680 javascript callback node.js promise bluebird
我想使用promises,但我有一个回调API,格式如下:
window.onload; // set to callback
...
window.onload = function() {
};
Run Code Online (Sandbox Code Playgroud)
function request(onChangeHandler) {
...
}
request(function() {
// change happened
...
});
Run Code Online (Sandbox Code Playgroud)
function getStuff(dat, callback) {
...
}
getStuff("dataParam", function(err, data) {
...
})
Run Code Online (Sandbox Code Playgroud)
API;
API.one(function(err, data) {
API.two(function(err, data2) {
API.three(function(err, data3) {
...
});
});
});
Run Code Online (Sandbox Code Playgroud)
Ben*_*aum 704
承诺有状态,他们开始等待,并可以解决:
承诺返回函数永远不应该抛出,它们应该返回拒绝.从承诺返回函数中抛出将强制您同时使用a } catch {
和 a .catch
.使用promisified API的人不希望承诺投掷.如果您不确定异步API在JS中是如何工作的 - 请先查看此答案.
因此,创建承诺通常意味着指定它们何时结算 - 这意味着它们何时转移到已完成或被拒绝的阶段以指示数据可用(并且可以访问.then
).
使用现代承诺实现支持Promise
构造函数,如本机ES6承诺:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Run Code Online (Sandbox Code Playgroud)
然后,您将使用生成的承诺,如下所示:
load().then(function() {
// Do things after onload
});
Run Code Online (Sandbox Code Playgroud)
使用支持延迟的库(让我们在这里使用$ q这个例子,但我们稍后也会使用jQuery):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Run Code Online (Sandbox Code Playgroud)
或者使用类似API的jQuery,挂钩一次发生的事件:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
Run Code Online (Sandbox Code Playgroud)
这些API很常见,因为...回调在JS中很常见.让我们来看看有onSuccess
和的常见情况onFail
:
function getUserData(userId, onLoad, onFail) { …
Run Code Online (Sandbox Code Playgroud)
使用现代承诺实现支持Promise
构造函数,如本机ES6承诺:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
Run Code Online (Sandbox Code Playgroud)
使用支持延迟的库(我们在这里使用jQuery这个例子,但我们也使用了上面的$ q):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
Run Code Online (Sandbox Code Playgroud)
jQuery还提供了一个$.Deferred(fn)
表单,它的优点是允许我们编写一个非常接近new Promise(fn)
表单的表达式,如下所示:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Run Code Online (Sandbox Code Playgroud)
注意:这里我们利用jQuery延迟resolve
和reject
方法是"可拆卸" 的事实; 即.它们绑定到jQuery.Deferred()的实例.并非所有的lib都提供此功能.
节点样式回调(nodebacks)具有特定格式,其中回调始终是最后一个参数,其第一个参数是错误.让我们首先手动宣传一个:
getStuff("dataParam", function(err, data) { …
Run Code Online (Sandbox Code Playgroud)
至:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
Run Code Online (Sandbox Code Playgroud)
使用deferreds,你可以执行以下操作(让我们使用Q作为这个例子,虽然Q现在支持你更喜欢的新语法):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
Run Code Online (Sandbox Code Playgroud)
一般来说,你不应该手动过多地宣传一些东西,大多数承诺在设计时考虑到Node以及Node 8+中的本机承诺的库都有内置的方法来实现节点回发.例如
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
Run Code Online (Sandbox Code Playgroud)
这里没有黄金法则,你一个接一个地宣传它们.但是,一些promise实现允许您批量执行此操作,例如在Bluebird中,将nodeback API转换为promise API非常简单:
Promise.promisifyAll(API);
Run Code Online (Sandbox Code Playgroud)
或与原生承诺在节点:
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Run Code Online (Sandbox Code Playgroud)
笔记:
.then
处理程序中时,你不需要宣传事物.从.then
处理程序返回承诺将使用该承诺的值来解决或拒绝.从.then
处理程序中投掷也是很好的做法,并且会拒绝承诺 - 这是着名的承诺投掷安全.onload
情况中,您应该使用addEventListener
而不是onX
.efk*_*kan 50
今天,我可以用Promise
在Node.js
作为一个普通的JavaScript方法.
一个简单而基本的例子Promise
(用KISS方式):
普通的 Javascript异步API代码:
function divisionAPI (number, divider, successCallback, errorCallback) {
if (divider == 0) {
return errorCallback( new Error("Division by zero") )
}
successCallback( number / divider )
}
Run Code Online (Sandbox Code Playgroud)
Promise
Javascript异步API代码:
function divisionAPI (number, divider) {
return new Promise(function (fulfilled, rejected) {
if (divider == 0) {
return rejected( new Error("Division by zero") )
}
fulfilled( number / divider )
})
}
Run Code Online (Sandbox Code Playgroud)
(我建议访问这个美丽的来源)
也Promise
可以一起使用async\await
的ES7
,以使程序流程等待一个fullfiled
类似如下的结果:
function getName () {
return new Promise(function (fulfilled, rejected) {
var name = "John Doe";
// wait 3000 milliseconds before calling fulfilled() method
setTimeout (
function() {
fulfilled( name )
},
3000
)
})
}
async function foo () {
var name = await getName(); // awaits for a fulfilled result!
console.log(name); // the console writes "John Doe" after 3000 milliseconds
}
foo() // calling the foo() method to run the code
Run Code Online (Sandbox Code Playgroud)
使用.then()
方法使用相同代码的另一种用法
function getName () {
return new Promise(function (fulfilled, rejected) {
var name = "John Doe";
// wait 3000 milliseconds before calling fulfilled() method
setTimeout (
function() {
fulfilled( name )
},
3000
)
})
}
// the console writes "John Doe" after 3000 milliseconds
getName().then(function(name){ console.log(name) })
Run Code Online (Sandbox Code Playgroud)
Promise
也可以在任何基于Node.js的平台上使用react-native
.
奖励:混合方法
(假设回调方法有两个参数作为错误和结果)
function divisionAPI (number, divider, callback) {
return new Promise(function (fulfilled, rejected) {
if (divider == 0) {
let error = new Error("Division by zero")
callback && callback( error )
return rejected( error )
}
let result = number / divider
callback && callback( null, result )
fulfilled( result )
})
}
Run Code Online (Sandbox Code Playgroud)
上述方法可以响应旧时尚回调和Promise使用的结果.
希望这可以帮助.
Siv*_*nan 30
在Node.JS中将函数转换为promise之前
var request = require('request'); //http wrapped module
function requestWrapper(url, callback) {
request.get(url, function (err, response) {
if (err) {
callback(err);
}else{
callback(null, response);
}
})
}
requestWrapper(url, function (err, response) {
console.log(err, response)
})
Run Code Online (Sandbox Code Playgroud)
转换后
var request = require('request');
function requestWrapper(url) {
return new Promise(function (resolve, reject) { //returning promise
request.get(url, function (err, response) {
if (err) {
reject(err); //promise reject
}else{
resolve(response); //promise resolve
}
})
})
}
requestWrapper('http://localhost:8080/promise_request/1').then(function(response){
console.log(response) //resolve callback(success)
}).catch(function(error){
console.log(error) //reject callback(failure)
})
Run Code Online (Sandbox Code Playgroud)
如果你需要处理多个请求
var allRequests = [];
allRequests.push(requestWrapper('http://localhost:8080/promise_request/1'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/2'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/5'))
Promise.all(allRequests).then(function (results) {
console.log(results);//result will be array which contains each promise response
}).catch(function (err) {
console.log(err)
});
Run Code Online (Sandbox Code Playgroud)
Leo*_*Leo 22
我不认为window.onload
@Benjamin 的建议会一直有效,因为它不会检测是否在加载后调用它.我被这多次咬过了.这是一个应该始终有效的版本:
function promiseDOMready() {
return new Promise(function(resolve) {
if (document.readyState === "complete") return resolve();
document.addEventListener("DOMContentLoaded", resolve);
});
}
promiseDOMready().then(initOnLoad);
Run Code Online (Sandbox Code Playgroud)
Jos*_*iah 15
来自未来
我通常使用的一个简单的通用函数。
const promisify = (fn, ...args) => {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
Run Code Online (Sandbox Code Playgroud)
如何使用它
promisify(fn, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)
您可能不是在寻找这个答案,但这将有助于了解可用工具的内部工作原理
Gia*_*rdi 14
Node.js 8.0.0包含一个新util.promisify()
API,它允许将标准Node.js回调样式API包装在返回Promise的函数中.示例用法util.promisify()
如下所示.
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
readFile('/some/file')
.then((data) => { /** ... **/ })
.catch((err) => { /** ... **/ });
Run Code Online (Sandbox Code Playgroud)
请参阅改进的Promise支持
Bru*_*uno 13
在Node.js 8.0.0的候选版本中,有一个新的实用程序util.promisify
(我写过关于util.promisify),它封装了宣传任何函数的能力.
它与其他答案中提出的方法没有太大的不同,但具有作为核心方法的优点,并且不需要额外的依赖性.
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
Run Code Online (Sandbox Code Playgroud)
然后你有一个readFile
返回原生的方法Promise
.
readFile('./notes.txt')
.then(txt => console.log(txt))
.catch(...);
Run Code Online (Sandbox Code Playgroud)
使用普通的旧版 javaScript,这是一个承诺 api 回调的解决方案。
function get(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.addEventListener('readystatechange', function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('successful ... should call callback ... ');
callback(null, JSON.parse(xhr.responseText));
} else {
console.log('error ... callback with error data ... ');
callback(xhr, null);
}
}
});
xhr.send();
}
/**
* @function promisify: convert api based callbacks to promises
* @description takes in a factory function and promisifies it
* @params {function} input function to promisify
* @params {array} an array of inputs to the function to be promisified
* @return {function} promisified function
* */
function promisify(fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return new Promise(function(resolve, reject) {
fn.apply(null, args.concat(function (err, result) {
if (err) reject(err);
else resolve(result);
}));
});
}
}
var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
// corresponds to the resolve function
console.log('successful operation: ', data);
}, function (error) {
console.log(error);
});
Run Code Online (Sandbox Code Playgroud)
您可以在Node JS中使用JavaScript本机承诺.
My Cloud 9代码链接:https://ide.c9.io/adx2803/native-promises-in-node
/**
* Created by dixit-lab on 20/6/16.
*/
var express = require('express');
var request = require('request'); //Simplified HTTP request client.
var app = express();
function promisify(url) {
return new Promise(function (resolve, reject) {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
reject(error);
}
})
});
}
//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
//get the post with post id 100
promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
var obj = JSON.parse(result);
return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
})
.catch(function (e) {
console.log(e);
})
.then(function (result) {
res.end(result);
})
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
//run webservice on browser : http://localhost:8081/listAlbums
Run Code Online (Sandbox Code Playgroud)
kriskowal的Q库包含应答回调函数。这样的方法:
obj.prototype.dosomething(params, cb) {
...blah blah...
cb(error, results);
}
Run Code Online (Sandbox Code Playgroud)
可以用Q.ninvoke转换
Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});
Run Code Online (Sandbox Code Playgroud)
当您有一些需要回调的函数并且希望它们返回承诺时,您可以使用此函数来进行转换。
function callbackToPromise(func){
return function(){
// change this to use what ever promise lib you are using
// In this case i'm using angular $q that I exposed on a util module
var defered = util.$q.defer();
var cb = (val) => {
defered.resolve(val);
}
var args = Array.prototype.slice.call(arguments);
args.push(cb);
func.apply(this, args);
return defered.promise;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
在内置了 Promise 和 async 的 Node v7.6+ 下:
// promisify.js
let promisify = fn => (...args) =>
new Promise((resolve, reject) =>
fn(...args, (err, result) => {
if (err) return reject(err);
return resolve(result);
})
);
module.exports = promisify;
Run Code Online (Sandbox Code Playgroud)
如何使用:
let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);
async function myAsyncFn(path) {
let entries = await readdirP(path);
return entries;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
203573 次 |
最近记录: |