代码之家  ›  专栏  ›  技术社区  ›  vibhor1997a

如果未传递可选回调,如何使函数返回承诺?

  •  0
  • vibhor1997a  · 技术社区  · 7 年前

    我可以想出

     function squareAsync(val, callback) {
    if (callback) {
        setTimeout(() => {
            if (Math.random() < 0.5) {
                callback(undefined, val * val);
            }
            else {
                callback(new Error('Failed!'));
            }
        }, 2000);
    }
    else {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if (Math.random() < 0.5) {
                    resolve(val * val);
                }
                else {
                    reject(new Error('Failed!'));
                }
            }, 2000);
       });
     }
    }
    

    我找到了另一个办法

     function squareAsync1(val, callback) {
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.5) {
                resolve(val * val);
            }
            else {
                reject(new Error('Failed!'));
            }
        }, 2000);
    });
    if (callback) {
        p.then(d => {
            callback(undefined, d);
        }, e => {
            callback(e);
        });
     }
    return p;
    }
    

    哪一个更好,或者有一个更标准和优雅的方式这样做?我们能不能用 async/await ?

    2 回复  |  直到 7 年前
        1
  •  1
  •   yqlim    7 年前

    你可以这样做:

    function squareAsync(val, callback) {
      const timeout = function(res, rej){
        setTimeout(function(){
          if (Math.random() < 0.5)
            res(val*val);
          else
            rej(new Error('Failed!'));
        }, 2000);
      }
      
      return typeof callback === 'function'
        ? timeout(callback.bind(null, undefined), callback)
        : new Promise(timeout);
    }
    
    // CALLBACK EXAMPLE
    squareAsync(5, (err, val) => {
      if (err)
        console.log(`Callback: ${err}`);
      else
        console.log(`Callback: ${val}`);
    })
    
    // PROMISE EXAMPLE
    squareAsync(5)
      .then(val => console.log(`Promise: ${val}`))
      .catch(err => console.log(`Promise: ${err}`))

    解释

    1. 把你的 setTimeout 调用一个包装函数 timeout 这样你就不用重复几乎相同的代码了。
    2. 超时 函数有两个参数: res rej (解决并拒绝)
    3. 返回 超时 如果回调与函数一起传递,则返回 new Promise(timeout) .

    现在关于发生在:

    return typeof callback === 'function'
      ? timeout(callback.bind(null, undefined), callback)
      : new Promise(timeout);
    

    它转化为:

    if (typeof callback === 'function'){
      // Bind `null` as `this` value to `callback
      // and `undefined` as its first argument (because no error).
      // Need to to this because in `timeout` function,
      // we call `res` with only 1 argument (computed value) if success.
      const resolve = callback.bind(null, undefined);
    
      // Don't need to bind anything
      // because the first argument should be error.
      const reject = callback;
    
      // Call the function as if we are in a Promise
      return timeout(resolve, reject);
    }
    
    // Use `timeout` function as normal promise callback.
    return new Promise(timeout);
    

    希望你能理解。如果感到困惑,请随意评论。

    More about bind.

        2
  •  1
  •   marcelotokarnia    7 年前
     async function squareAsync1(val, callback) {
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() < 0.5) {
                resolve(val * val);
            }
            else {
                reject(new Error('Failed!'));
            }
        }, 2000);
    });
    if (callback) {
        return p.then(d => {
            return callback(undefined, d);
        }, e => {
            return callback(e);
        });
     }
    return p;
    }
    

    是的,您的解决方案将使用async/await。注意我刚刚加了 return 给警察

    这样你就可以做如下事情:

    const x = await squareAsync1(2, (e, v) => e ? 1 : v * 2)
    

    你会得到 x 作为1(如果承诺被拒绝)或8(如果承诺成功)