我想使用promise,但我有一个回调API,格式如下:

1.DOM加载或其他一次性事件:

window.onload; // set to callback
...
window.onload = function() {

};

2.普通回调:

function request(onChangeHandler) {
    ...
}
request(function() {
    // change happened
    ...
});

3.节点样式回调(“nodeback”):

function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
})

4.具有节点样式回调的整个库:

API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

我如何在promise中使用API,如何“promise”它?


当前回答

你可以这样做

// @flow

const toPromise = (f: (any) => void) => {
  return new Promise<any>((resolve, reject) => {
    try {
      f((result) => {
        resolve(result)
      })
    } catch (e) {
      reject(e)
    }
  })
}

export default toPromise

然后使用它

async loadData() {
  const friends = await toPromise(FriendsManager.loadFriends)

  console.log(friends)
}

其他回答

您可以在NodeJS中使用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

在内置promise和异步的节点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;

如何使用:

let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);

async function myAsyncFn(path) {
    let entries = await readdirP(path);
    return entries;
}

承诺总是有决心和拒绝。当您编写异步包装器时,只需调用resolve即可。

您可以为几乎所有接受回调的函数编写包装函数,如下所示:

const myAsyncWrapper = (...params) =>
  new Promise((resolve, reject) => 
    someFunctionWithCallback(...params, (error, response) =>
      error ? reject(error) : resolve(response)
    )
  );

您可以进一步编写回调到promise的转换函数:

const promisify =
  (functionWithCallback) =>
  (...params) =>
    new Promise((resolve, reject) =>
      functionWithCallback(...params, (error, response) =>
        error ? reject(error) : resolve(response)
      )
    );

当使用较旧的库或SDK时,包装函数的概念尤其有用。例如,考虑FacebookGraph API的JavaScriptSDK,它使用类似的回调结构来发出API请求。

FB.api(apiURL, options, function (request) {
  if (request.error || !request) return;
  // handle request
});

在现代应用程序中,使用基于承诺的API更有用。如果您只使用一个函数一次或两次,则最好单独给出响应:

// in an async function
const response = await new Promise((resolve, reject) =>
  FB.api(apiURL, (res) => (res?.error ? reject(res?.error) : resolve(res)))
);

如果经常使用该函数,可以使用相同的包装器概念来编写如下函数:

const apiWrapper = (...params) =>
  new Promise((resolve, reject) => 
    FB.api(...params, (res) => (res?.error ? reject(res?.error) : resolve(res)))
  );

虽然promisifier有时很好,但它们不适用于这样的特定实例。在这种情况下,在Github上寻找一个现代的包装器,或者像这样编写自己的包装器。

Node.js 8.0.0包含一个新的util.provisify()API,它允许将标准Node.js回调样式的API封装在返回Promise的函数中。下面显示了util.provisify()的示例用法。

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

readFile('/some/file')
  .then((data) => { /* ... */ })
  .catch((err) => { /* ... */ });

请参阅改进对承诺的支持

我通常使用的一个简单的泛型函数。

const promisify = (fn, ...args) => {
  return new Promise((resolve, reject) => {
    fn(...args, (err, data) => {
      if (err) {
        return reject(err);
      }
      resolve(data);
    });
  });
};

如何使用它

函数promify接受带有回调的函数:

   const cb = (result) => `The result is ${result}`;

   const sum = (a, b, cb) => {
    const result = a + b;
    cb(result); // passing args to the callback function
   }


  // using the util
  promise = promisify(sum, 3, 1, cb);
  promise.then(x => console.log(x)) // 4

您可能不需要这个答案,但这将有助于了解可用实用程序的内部工作原理