2

我在与承诺作斗争。我看到事件链是如何发生的,.then().then().then().then().then().then().then().then().then().then().then().then()但我不知道如何让它结束。我希望我可以做一个简单的:

 .then(callback(mydata))

但是,我无法让它发挥作用。我正在努力做到这一点。

function doSomethingCallback(theArrayComesBackHere) {
    theArrayComesBackHere.forEach(/*do stuff*/);
}    

button.onclick = () => {
   myobj.getlocalforagedata(doSomethingCallback);
}

myobj = {
   getlocalforagedata: (callback) => {
      var arr = [];
      localForage.keys().then((keys) => {
          keys.forEach((key) => {
              localForage.getItem(key).then(function (results) {
                  arr.push(results);
              });
          });
          callback && callback(arr);
      });
   }
}

请帮助我摆脱这种疯狂。

4

3 回答 3

4

[以前] 接受的这个问题的答案是使用显式承诺创建反模式,这种做法使代码更加复杂和错误。

您可以更干净地完成您想要做的事情,如下所示:

function getLocalForageData() {
    return localForage.keys().then(function (keys) {
        return Promise.all(keys.map(function (key) {
            return localForage.getItem(key);
        });
    });
}

示例用法:

getLocalForageData()
    .then(function (values) {
        console.log(values);
    })
    .catch(function (error) {
        console.error(error);
    });

上面获得了一个值数组,这些值与它们各自的键不匹配。如果您希望值与它们的键配对,您可以这样做:

function getLocalForageData() {
    return localForage.keys().then(function (keys) {
        return Promise.all(keys.map(function (key) {
            return localForage.getItem(key)
                .then(function (value) {
                    return { key: key, value: value };
                });
        }));
    });
}

或者你可以打破一个内部函数来减少嵌套:

function getLocalForageValueWithKey(key) {
    return localForage.getItem(key)
        .then(function (value) {
            return { key: key, value: value };
        });
}

function getLocalForageData() {
    return localForage.keys().then(function (keys) {
        return Promise.all(keys.map(getLocalForageValueWithKey));
    });
}

无论哪种情况,调用和使用该getLocalForageData函数的代码都与上述相同。

于 2017-11-10T19:05:16.743 回答
1

[编辑] JLRishe的答案还不错,但它返回了一个对象数组,下次使用时很难读取(你需要一个循环来获取值),而且似乎忘记了null值,所以完整和诡计的解决方案应该更多喜欢:

  const getLocalForageDataByKeys = () => {
    return localForage.keys().then(keys => {
      return Promise.all(keys.map(key => {
        return localForage.getItem(key)
          .then(value => {
            return { [key]: value }
          })
          .catch(error => {
            console.log(error)
            return { [key]: null }
          })
      })).then(arr => {
        return Object.assign(...arr)
      })
    })
  }

用法:

getLocalForageDataByKeys()
  .then(obj => {
    console.log(obj) // { keyA: 'valueA', keyB: 'valueB' }
  }).catch(error => {
    console.log(error) // do sth with error
  })

笔记:

更好的是,这个解决方案使用ES6jsLint最高质量标准

更多的:

承诺示例localForagehttps ://localforage.github.io/localForage/#data-api-getitem

使用承诺:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

使用对象分配:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

使用扩展运算符:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

于 2017-11-10T17:50:12.827 回答
0

问题中代码的几个功能不是必需的:

  • new Promise(...): localForage.keys()返回一个构成 Promise 链根的 Promise。
  • callback通过从 中返回一个承诺getlocalforagedata(),调用者可以链接getlocalforagedata().then(...)避免传递回调的需要。
  • 外部变量arr一个正确构建的承诺链可以在没有任何外部变量的情况下收集和交付结果。

以下是必要的:

  • 聚合localForage.getItem(key)返回的承诺,并从链中的该步骤返回承诺。
  • 执行测试if (err.length > 0)并在等待承诺解决if (arr.length > 0)的进一步链中。.then()localForage.getItem(key)

尝试这个 :

myobj = {
    getlocalforagedata: () => {
        return localForage.keys()
        .then(keys => {
            // Use `keys.map(...)` to return an array of promises.
            // Then use `Promsie.all()` to aggregate the promises returned by `localForage.getItem(key)`.
            return Promise.all(keys.map(key => localForage.getItem(key)));
        })
        .then(arr => { // an array of results
            // These tests must be performed in a chained `then()`,
            // which will wait for all the individual `localForage.getItem(key)` results (or errors) to be delivered
            if (arr.length > 0) {
                return arr; // deliver a non-empty array
            } else {
                throw new Error('no results'); // throw error down the promise chain's error path.
            }
        });
    }
}

调用如下:

myobj.getlocalforagedata()
.then((results) => {
    // Work with results
})
.catch((error) => {
    // Do whatever with error.
    // Either return some default value or re-throw `error`
});

getlocalforagedata()可以使用回调来工作,但最好的做法是返回一个承诺并允许调用者链接getlocalforagedata().then(...)

于 2017-11-10T19:06:50.990 回答